Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control Characters and String Manipulation

Using the trick posted on ss64 by Jeb to save the backspace control character into a variable - I get strange results when 'overlapping' backspaces.

The example is in a code golfing challenge posted here: Backhanded^H^H^H^H^H^Hspaces (would appreciate any tips to get this code shorter).

Ungolfed it could look like this:

@echo off
setLocal enableDelayedExpansion

for /F %%a in ('"prompt $H&echo on&for %%b in (1) do rem"') do set DEL=%%a

set s=%1
echo %s:^H=!DEL!%

Basically, it uses Jeb's trick to save backspace as a variable, then uses string manipulation to replace all instances of ^H in the input string with that variable. Which works correctly for the following example, and similar inputs:

C:\>bsp.bat "testing^H^H^H test"
"test test"

However when 'overlapping' usage of ^H occurs, I get the following confusing (to me) output:

C:\>bsp.bat "AAA^HB^H^H"
"A"B

My question is - with the above example, why am I receiving this output instead of the expected "A"?

like image 399
unclemeat Avatar asked Feb 17 '26 14:02

unclemeat


2 Answers

I don't understand why the "expected output" should be "A". See this character-by-character output:

bsp.bat "AAA^HB^H^H"
"
"A
"AA
"AAA
"AAA    <- backspace, the cursor is over last "A"
"AAB
"AAB    <- backspace, the cursor is over last "B"
"AAB    <- backspace, the cursor is over second "A"
"A"B

The BS character just moves the cursor one character back. The "standard behaviour" of BackSpace key (also called "BackSpace echo") is "BackSpace+space+BackSpace".

By the way, this is the method I used to get BS character:

for /F %%a in ('echo prompt $H ^| cmd') do set BS=%%a
like image 52
Aacini Avatar answered Feb 20 '26 06:02

Aacini


The "A"B result is to be expected because the backspace character (0x08) <BS> only moves the cursor back without erasing the character.

When you use PROMPT $H, it actually prints <BS><space><BS>. The first <BS> moves back one, the space overwrites (visually clears) the character, and then the 2nd <BS> moves back again to where you want to be.

The default delimiter with FOR /F is <tab><space>, so your assignment only preserves the first <BS>. Change the delimter to "r" and you get your desired result:

@echo off
setLocal enableDelayedExpansion

for /F "delims=r" %%a in ('"prompt $H&echo on&for %%b in (1) do rem"') do set DEL=%%a

set s=%1
echo %s:^H=!DEL!%

Or, preserve the single <bs> definition and explicitly overwrite the character yourself:

@echo off
setLocal enableDelayedExpansion

for /F %%a in ('"prompt $H&echo on&for %%b in (1) do rem"') do set DEL=%%a

set s=%1
echo %s:^H=!DEL! !DEL!%
like image 23
dbenham Avatar answered Feb 20 '26 07:02

dbenham