8

Besides SED, how can an equal sign be replaced? And how can I use a string variable in string replacement?

Consider this example:

For /F "tokens=*" %%B IN (test.txt) DO (
   SETLOCAL ENABLEDELAYEDEXPANSION
   SET t=is
   SET old=%%B
   SET new=!old:t=!
   ECHO !new!

   ENDLOCAL
)

:: SET new=!old:==!

Two problems:

First, I cannot use the variable %t% in !:=!.

   SET t=is
   SET old=%%B
   SET new=!old:t=!

Second, I cannot replace the equal sign in the command line

   SET new=!old:==!
Joey
  • 344,408
  • 85
  • 689
  • 683
Tin Amaranth
  • 683
  • 2
  • 12
  • 23

7 Answers7

8

I just created a simple solution for this myself, maybe it helps someone.

The disadvantage (or advantage, depends on what you want to do) is that multiple equal signs one after another get handled like one single equal sign. (example: "str==ing" gives the same output as "str=ing")

@echo off
set "x=this is=an test="
echo x=%x%

call :replaceEqualSign in x with _
echo x=%x%

pause&exit


:replaceEqualSign in <variable> with <newString>
    setlocal enableDelayedExpansion

        set "_s=!%~2!#"
        set "_r="

        :_replaceEqualSign
            for /F "tokens=1* delims==" %%A in ("%_s%") do (
                if not defined _r ( set "_r=%%A" ) else ( set "_r=%_r%%~4%%A" )
                set "_s=%%B"
            )
        if defined _s goto _replaceEqualSign

    endlocal&set "%~2=%_r:~0,-1%"
exit /B

As you have seen, you use the function like this:

call :replaceEqualSign in variableName with newString
timlg07
  • 547
  • 6
  • 20
3

The setlocal enableDelayedExpansion should be moved after your old=%%B assignment in case %%B contains !.

The "t" problem is easy to solve within a loop by using another FOR variable

For /F "tokens=*" %%B IN (test.txt) DO (
   SET t=is
   SET old=%%B
   SETLOCAL ENABLEDELAYEDEXPANSION
   for /f %%T in ("!t!") do SET new=!old:%%T=!
   ECHO !new!
   ENDLOCAL
)

There is no simple native batch solution for replacing =. You can iterate through the string, character by character, but that is slow. Your best bet is probably to switch to VBScript or JScript, or use a non-native utility.

If you really want to do this using pure Windows batch commands, there are a couple of interesting ideas at http://www.dostips.com/forum/viewtopic.php?t=1485

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • 1
    I see. Maybe I need to approach VBScript, VB or C#. It seems they're an advanced version of DOS Command. How about if the text is like this: This is an apple. This is a cat. Using the codes gets rid of all the "is". We do know how to do whole word only replace in VB but how about in DOS Command? Is it impossible? The same to the equal sign case? – Tin Amaranth Mar 05 '12 at 16:45
  • If you only want to replace whole words, then batch script is not a good option. It can be approximated, but you would be much better off using something that supports regex search and replace, such as VBScript. – dbenham Mar 06 '12 at 04:21
  • Yes. I see. Thanks for pointing me to the suitable languages. – Tin Amaranth Mar 07 '12 at 01:55
  • "Maybe I need to approach VBScript, VB or C#. It seems they're an advanced version of DOS Command." +1 for "C# is an advanced version of DOS Command"... – Christian Severin Oct 29 '12 at 13:48
2

UPDATE: The latest version is here: https://github.com/andry81/contools (https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/)

You can use some sequence to temporary replace special characters by placeholders like ?00, ?01, ?02 and ?03. I basically use these set of scripts:

replace_sys_chars.bat:

@echo off

rem Description:
rem   Script to replace ?, !, %, and = characters in variables by respective
rem   ?00, ?01, ?02 and ?03 placeholders.

setlocal DISABLEDELAYEDEXPANSION

set "__VAR__=%~1"

if "%__VAR__%" == "" exit /b 1

rem ignore empty variables
call set "STR=%%%__VAR__%%%"
if "%STR%" == "" exit /b 0

set ?01=!

call set "STR=%%%__VAR__%:?=?00%%"
set "STR=%STR:!=?01%"

setlocal ENABLEDELAYEDEXPANSION

set STR=!STR:%%=?02!
set "STR_TMP="
set INDEX=1

:EQUAL_CHAR_REPLACE_LOOP
set "STR_TMP2="
for /F "tokens=%INDEX% delims== eol=" %%i in ("/!STR!/") do set STR_TMP2=%%i
if "!STR_TMP2!" == "" goto EQUAL_CHAR_REPLACE_LOOP_END
set "STR_TMP=!STR_TMP!!STR_TMP2!?03"
set /A INDEX+=1
goto EQUAL_CHAR_REPLACE_LOOP

:EQUAL_CHAR_REPLACE_LOOP_END
if not "!STR_TMP!" == "" set STR=!STR_TMP:~1,-4!

(
  endlocal
  endlocal
  set "%__VAR__%=%STR%"
)

exit /b 0

restore_sys_chars.bat:

@echo off

rem Description:
rem   Script to restore ?, !, %, and = characters in variables from respective
rem   ?00, ?01, ?02 and ?03 placeholders.

setlocal DISABLEDELAYEDEXPANSION

set "__VAR__=%~1"

if "%__VAR__%" == "" exit /b 1

rem ignore empty variables
call set "STR=%%%__VAR__%%%"
if "%STR%" == "" exit /b 0

setlocal ENABLEDELAYEDEXPANSION

set STR=!STR:?02=%%!
set STR=!STR:?03==!

(
  endlocal
  set "STR=%STR%"
)

set "STR=%STR:?01=!%"
set "STR=%STR:?00=?%"

(
  endlocal
  set "%__VAR__%=%STR%"
)

exit /b 0

Example:

@echo off

setlocal DISABLEDELAYEDEXPANSION

for /F "usebackq tokens=* delims=" %%i in ("test.txt") do (
  set VALUE=%%i
  call :PROCESS
)
exit /b 0

:PROCESS
if "%VALUE%" == "" exit /b 0

set "VALUE_=%VALUE%"
call replace_sys_chars.bat VALUE_

rem do variable arithmetic here as usual
if not "%VALUE_:?00=%" == "%VALUE_%" echo."%VALUE%" having ?
if not "%VALUE_:?01=%" == "%VALUE_%" echo."%VALUE%" having !
if not "%VALUE_:?02=%" == "%VALUE_%" echo."%VALUE%" having %%
if not "%VALUE_:?03=%" == "%VALUE_%" echo."%VALUE%" having =

rem restore it
call restore_sys_chars.bat VALUE_
echo "VALUE=%VALUE_%"

echo.---

test.txt:

111/222
AAA=BBB
CCC=%DDD%
EEE=!FFF!
FFF=?00?01?02?03

Result:

"VALUE=111/222"
---
"AAA=BBB" having =
"VALUE=AAA=BBB"
---
"CCC=%DDD%" having %
"CCC=%DDD%" having =
"VALUE=CCC=%DDD%"
---
"EEE=!FFF!" having !
"EEE=!FFF!" having =
"VALUE=EEE=!FFF!"
---
"FFF=?00?01?02?03" having ?
"FFF=?00?01?02?03" having =
"VALUE=FFF=?00?01?02?03"
---

Features:

  • You can continue use standard batch variable arithmetic between conversions
  • You can use character placeholders (?00, ?01, ?02, ?03) as plain variable values
Andry
  • 2,273
  • 29
  • 28
1

Why not use Edlin? I could not find a way to do this with one initial file and no errors from Edlin, but just ignore them with NUL:. Strangly, the TYPE %0 includes the whole file even if there's an end of file character between the = and !, using TYPE on the batch file after it has run will not work the same way.

@ECHO OFF
GOTO skip
1,1r=!
e
:skip

SET "new==old============="

ECHO %new% > %TEMP%\var.tmp
TYPE %0 > %TEMP%\edlin.tmp

EDLIN %TEMP%\var.tmp < %TEMP%\edlin.tmp > NUL:

SET /P newnew=<%TEMP%\VAR.TMP
ECHO %newnew%

ERASE %TEMP%\VAR.TMP
ERASE %TEMP%\VAR.BAK
ERASE %TEMP%\edlin.tmp
Erbert
  • 321
  • 1
  • 3
  • 8
  • The end of file character got deleted when I posted. It should be between the = and ! on the third line. – Erbert Mar 23 '12 at 01:45
0

I was looking into this, because I needed to get rid of = in a string like "test=goingon" I found that calling a next batchfile with test=goingon as parameters, I have parameters 1, "test" and 2, "goingon", in that batchfile.

So: batchfile 1:

@echo off
call test2.bat test=goingon

batchfile2:

echo arg1: %1
echo arg2: %2

result:

arg1: test
arg2: goingon
0

I used Bosj's idea to come up with this. It works.

set s=Abra=Cadabra
echo now you see it  %s%
call :ReplaceEqual %s%
echo  now you don't  %s%
exit /b
:ReplaceEqual
set s=%1_%2
exit /b
  • 2
    But it also "works" if you have `Abra Cadabra` or `Abra;Cadabra` or `Abra,Cadabra` and it doesn't "work" for `Abra Abra=Cadabra` or `Abra====Cadabra` – Magoo Apr 06 '22 at 00:24
-1

My answer from another post, but it applies here, too:

There is an alternative that is easier. Instead of passing in a value that contains an equals sign, try something like a colon instead. Then, through the ability to modify that value (the colon), you can convert it back into an equals. Here is an example:

@echo off
set VALUE1=%1
set VALUE2=%VALUE1::==%
echo value1 = %VALUE1%
echo value2 = %VALUE2%

When you run the batch file, call it like this:

C:\>myBatch name:someValue

The output would be:

value1 = name:someValue
value2 = name=someValue

If the name or value contains a space, you will have other issues to address, though. You will need to wrap the entire string in double quotes. But, then you have the issue of needing to get rid of them. This can also be handled, like this:

@echo off
cls
set PARAM=%1
set BASE=%PARAM:"=%
set PAIR=%BASE::==%

rem Either of these two lines will do the same thing - just notice the 'delims'
rem for /f "tokens=1,2 delims=:" %%a in ("%BASE%") do set NAME=%%a & set VALUE=%%b
rem for /f "tokens=1,2 delims==" %%a in ("%PAIR%") do set NAME=%%a & set VALUE=%%b

for /f "tokens=1,2 delims=:" %%a in ("%BASE%") do set NAME=%%a & set VALUE=%%b

echo param = %PARAM%
echo base  = %BASE%
echo pair  = %PAIR%
echo name  = %NAME%
echo value = %VALUE%

When running this batch file like this:

C:\>myBatch "some name:another value"

The output will be:

param = "some name:another value"
base  = some name:another value
pair  = some name=another value
name  = some name
value = another value

Hope that helps others in their quest to win the fight with batch files.

Mike V.

Mike Viens
  • 2,467
  • 3
  • 19
  • 23