maccam
maccam

Reputation: 3

CMD substitute phrase containing special characters

I need to do a very simple thing: substitute one frase with another. This must be done by CMD batch file (for Windows 7). The frase to be subsitituted can be in any position in txt file line (and in many lines).

The problem is the frase to be substituted contains ":" and "!" characters. I am not very skilled in batch files (to put it mildly), though I spend some hours especially to learn about this specific problem. It looks very complicated for me. At last, by chance, I overided the issue, but... I feel it is a barbarity how I did it.

The real line with the frase which should be substituted is e.g.:

"21:12:45 WARNING: No video signal present!"

The frase which should be substituted is:

"WARNING: No video signal present!"

The frase, which it should be substituted with is:

"Recognition suspended"

I have found this code: https://www.computerhope.com/forum/index.php?topic=41188.0

It works fine, except cannot work with "!" as I see, and escape char "^" never works. But I noticed that although it doesn't work properly - it trims the exclamation mark. Here are real strings before (b) and after (a):

(b)20:42:18 WARNING: No video signal present!
(a)20:42:18 WARNING: No video signal present

So I add 2 other lines to the code and this does the thing. The whole code is now:

@echo off
setlocal enabledelayedexpansion
set txtfile=D:\wfc\testlib\test.txt
set newfile=D:\wfc\testlib\new_test.txt
if exist "%newfile%" del /f /q "%newfile%"
for /f "tokens=*" %%a in (%txtfile%) do (
   set newline=%%a
   set newline=!newline:No video signal present!=!
   set newline=!newline:No video signal present=!
   set newline=!newline:WARNING:=Suspend recognition!
   echo !newline! >> %newfile%
)

First crucial line cuts "!", second line substitutes "No video signal present" with nothing (trims it), third line substitutes the rest "Warning:" with desirable "Suspend recognition".

And at the end I have:

(b)20:42:18 WARNING: No video signal present!
(a)20:42:18 Suspend recognition

I feel this could be done elegantly. Besides I am not sure, if my way is not dangerous for some reason (data damage etc.). Please help.

Upvotes: 0

Views: 121

Answers (2)

aschipfl
aschipfl

Reputation: 34919

Yes, this can be done easier.

First of all, it is not the line set newline=!newline:No video signal present!=! that removes the ! character, but it is the line set newline=%%a, because there is delayed variable expansion enabled when the for variable reference %%a is expanded, which happens before delayed expansion, hence an orphaned exclamation mark appears that is simply removed.

The key to success is to disable delayed expansion during expansion of %%a and to enable it afterwards. In the sub-string replacement syntax the : does not cause any problems; neither does the ! in the search string, given it is not the first character. So the following code should work:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "txtfile=D:\wfc\testlib\test.txt"
set "newfile=D:\wfc\testlib\new_test.txt"

> "%newfile%" (
    for /F usebackq^ delims^=^ eol^= %%a in ("%txtfile%") do (
        set "newline=%%a"
        setlocal EnableDelayedExpansion
        echo(!newline:WARNING: No video signal present!=Recognition suspended!
        endlocal
    )
)

endlocal
exit /B

I also changed the following items:

  • improved the syntax of set by using quotes to avoid trouble with some special characters;
  • avoided interim variable newline, so did the string manipulation directly in the echo line;
  • quoted file path/name to avoid problems with white-spaces, hence using usebackq option;
  • replaced the tokens=* by the delims= option in order to keep leading white-spaces; to avoid loss of lines that begin with ; due to the default eol option, I used the odd-looking unquoted option string syntax as this is the only way (!) to have no delims and eol defined at the same time (you cannot write "delims= eol=" as this would define " as the eol character; "eol= delims=" would define the SPACE, and "eol=delims=" the d);
  • redirected whole for loop, so no initial file deletion necessary, and the performance is a lot better, because the output file has to be opened and closed once only, not in every iteration;
  • echo Text > "file.ext" returns a trailing SPACE (actually the one in front of >); this is avoided by the above item; in general, this can be avoided when using the reversed redirection syntax > "file.ext" echo Text;
  • echo !VAR! returns ECHO is on|off. in case variable VAR is empty; to avoid this or other unexpected output, the odd-looking but safe syntax echo(!VAR! is used;
  • avoided immediate (%) expansion when delayed expansion is enabled to avoid loss of !;

To keep empty lines that appear in the original file, change the code to this:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "txtfile=D:\wfc\testlib\test.txt"
set "newfile=D:\wfc\testlib\new_test.txt"

> "%newfile%" (
    for /F "delims=" %%a in ('findstr /N /R "^" "%txtfile%"') do (
        set "newline=%%a"
        setlocal EnableDelayedExpansion
        set "newline=!newline:WARNING: No video signal present!=Recognition suspended!"
        echo(!newline:*:=!
        endlocal
    )
)

endlocal
exit /B

The findstr command is used to prefix every line of the input file by a line number plus a colon (/N option). Then the sub-string replacement is done. Finally, everything up to and including the first :, hence the line number prefix becomes removed.

Upvotes: 1

lit
lit

Reputation: 16236

Substituting a phrase is pretty easy to do in a .bat file script.

powershell -NoLogo -NoProfile -Command ^
    "Get-Content -Path '.\subfrase-in.txt' |" ^
        "ForEach-Object { $_ -replace 'WARNING: No video signal present!', 'Recognition suspended' }"

Upvotes: 0

Related Questions