Home Ask Login Register

Developers Planet

Your answer is one click away!

Arescet February 2016

How to escape "~" in set/replace command?

I'm trying to replace all instances of ~ with {~} in a batch script so that VBScript doesn't assume I mean to hit enter when I pass it to sendKeys, however, the variable keeps getting replaced by the literal string meant to replace it.

For example,

rem Intended function;
rem input  = Hello~world.
rem output = Hello{~}world.

However each time, it either does nothing, or sets refVar to the literal string refVar:~={~}.

Here's what I have tried;

set refVar=!refVar:~={~}!

rem Also
set refVar=%refVar:~={~}%

rem and...
set refVar=%refVar:^~=^{^~^}%

rem and of course;
set refVar=!refVar:^~=^{^~^}!

rem and even:

set "pre=~"
set "post={~}"
set refVar=%refVar:!pre!=!post!%

rem and the same set commands with;
set refVar=!refVar:%pre%=%post%!

Am I missing a way to escape this? I'm pretty sure it has to do with ~ being a positional character in a similar command.

I understand there's likely a way to fix this in VBScript, but this bothers me to have a restriction without apparent workarounds to me.

Answers


Dennis van Gils February 2016

So I did some digging and it seems this is really, really hard. However, I did find this, which solves the problem, giving us this as code:

@echo off

set "input=Hello~world."
echo input: %input%

call :wavereplacer "%input%" {tilde} output
set output=%output:{tilde}={~}%
echo output: %output%
pause

::your own code should be above this.
goto :eof

:wavereplacer String Replacer [RtnVar]
setlocal
rem  the result of the operation will be stored here
set "result=#%~1#"
set "replacer=%~2"
call :strlen0.3 result wl
call :strlen0.3 replacer rl

:start

  set "part1="
  set "part2="

  rem splitting the string on two parts
  for /f "tokens=1* delims=~" %%w in ("%result%") do (
   set "part1=%%w"
   set "part2=%%x"
  )

  rem calculating the count replace strings we should use
  call :strlen0.3 part1 p1l
  call :strlen0.3 part2 p2l
  set /a iteration_end=wl-p1l-p2l

  rem creating a sequence with replaced strings
  setlocal enableDelayedExpansion
  set "sequence="
  for /l %%i in (1,1,%iteration_end%) do (
   set sequence=!sequence!%replacer%
  )
  endlocal & set "sequence=%sequence%"

  rem adjust the string length
  set /a wl=wl+iteration_end*(rl-1)

  rem replacing for the current iteration
  set result=%part1%%sequence%%part2%
  rem if the second part is empty the task is over
  if "%part2%" equ "" (
   set result=%result:~1,-1%
   goto :endloop
  )


  goto :start

:endloop
endlocal & if "%~3" neq "" (set %~3=%result%) else echo %result%
exit /b

:strlen0.3  StrVar  [RtnVar]
  setlocal EnableDelayedExpansion
  set "s=#!%~1!"
  set "len=0"
  for %%A in (2187 729 243 81 27 9 3 1) do (
   set /A mod=2*%%A
   for %%Z in (!mod!) do (
      if "!s:~%%Z,1!" neq "" (
         set /a "len+=%%Z"
         set "s=!s:~%%Z!"

      ) else (
         if "!s:~%%A,1!" neq "" (
            set /a "len+=%%A"
            set "s=!s:~%%A!"
         )
      )
   )
   


Mofi February 2016

I offer a perhaps easier solution for replacing each tilde character in value string of an environment variable by a tilde in braces than Dennis van Gils which works also fine for this task.

@echo off
set "TestVar=hello~world."
echo TestVar has value: %TestVar%
call :SpecialReplace "TestVar"
echo TestVar has value: %TestVar%
goto :EOF


rem The subroutine below expects the name of an environment variable as
rem parameter. The subroutine does nothing if called without parameter.
rem Also nothing is done if specified environment variable is not defined.

rem Each tilde character in value of this environment variable is replaced
rem by {~} by this subroutine.

rem Note: This subroutine can be also easily modified to replace other
rem special characters like the equal sign by a different string which
rem can be also no string in case of special character should be removed.
rem Just modify Search and Replace variables for a different replace. But
rem be aware of more code must be changed if search string is longer than
rem one character. Length of replace string does not matter on code below.

:SpecialReplace
if "%~1" == "" exit /B
setlocal EnableDelayedExpansion
set "VarName=%~1"
set "VarValue=!%VarName%!"
if "!VarValue!" == "" endlocal & exit /B
set "NewValue="
set "Search=~"
set "Replace={~}"

:ReplaceLoop
if "!VarValue:~0,1!" == "!Search!" (
    set "NewValue=!NewValue!!Replace!"
) else (
    set "NewValue=!NewValue!!VarValue:~0,1!"
)
set "VarValue=!VarValue:~1!"
if not "!VarValue!" == "" goto ReplaceLoop
endlocal & set "%VarName%=%NewValue%" & exit /B

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /?
  • echo /?

Magoo February 2016

@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION 
SET "input=hello~world"

SET "xhead=!input:%input:*~=%=!"
SET "output=!input:%xhead%=%xhead:~0,-1%{~}!"

ECHO %input% --^> %output% 

GOTO :EOF

This appears to work provided there is exactly one ~ and that it's not the initial or terminal character.

Post Status

Asked in February 2016
Viewed 1,532 times
Voted 9
Answered 3 times

Search




Leave an answer


Quote of the day: live life