Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

batch-file

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.

like image 352
Bloodied Avatar asked Feb 06 '16 20:02

Bloodied


1 Answers

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!"
         )
      )
   )
  )
  endlocal & if "%~2" neq "" (set %~2=%len%) else echo %len%
exit /b

This cannot replace ~ to {~} immediately, you need to use a temporary substitution, in this case {tilde}

like image 69
Dennis van Gils Avatar answered Oct 02 '22 13:10

Dennis van Gils