包含特殊字符的 CMD 替换短语
Posted
技术标签:
【中文标题】包含特殊字符的 CMD 替换短语【英文标题】:CMD substitute phrase containing special characters 【发布时间】:2018-09-11 20:03:36 【问题描述】:我需要做一件非常简单的事情:用一个框架替换另一个框架。这必须通过 CMD 批处理文件完成(对于 Windows 7)。被替换的帧可以在txt文件行中的任意位置(也可以在多行中)。
问题是要替换的框架包含“:”和“!”人物。我对批处理文件不是很熟练(委婉地说),尽管我花了几个小时专门来了解这个特定问题。对我来说看起来很复杂。最后,一次偶然的机会,我忽略了这个问题,但是......我觉得我这样做是野蛮的。
应该替换的带有框架的实际行是例如:
"21:12:45 WARNING: No video signal present!"
应该替换的框架是:
"WARNING: No video signal present!"
它应该被替换的框架是:
"Recognition suspended"
我找到了这个代码:https://www.computerhope.com/forum/index.php?topic=41188.0
它工作正常,除了不能使用“!”如我所见,转义字符“^”永远不会起作用。但我注意到虽然它不能正常工作 - 它修剪了感叹号。以下是 (b) 之前和 (a) 之后的真实字符串:
(b)20:42:18 WARNING: No video signal present!
(a)20:42:18 WARNING: No video signal present
所以我在代码中添加了另外 2 行代码,这样就完成了。整个代码现在是:
@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%
)
第一个关键行剪切“!”, 第二行用任何内容替换“没有视频信号”(修剪它), 第三行将其余的“警告:”替换为理想的“暂停识别”。
最后我有:
(b)20:42:18 WARNING: No video signal present!
(a)20:42:18 Suspend recognition
我觉得这可以优雅地完成。此外,我不确定我的方式是否由于某种原因(数据损坏等)不危险。请帮忙。
【问题讨论】:
【参考方案1】:是的,这可以更容易地完成。
首先,删除!
字符的不是set newline=!newline:No video signal present!=!
这一行,而是set newline=%%a
这一行,因为for
变量引用%%a
时启用了delayed variable expansion扩展,这发生在延迟扩展之前,因此会出现一个孤立的感叹号,只需删除即可。
成功的关键是在%%a
的扩展过程中禁用延迟扩展,然后再启用它。在sub-string replacement syntax:
不会造成任何问题;搜索字符串中的!
也不是,因为它不是第一个字符。所以下面的代码应该可以工作:
@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
我还更改了以下项目:
改进了set
的语法,通过使用引号来避免一些特殊字符的麻烦;
避免了临时变量newline
,因此直接在echo
行中进行了字符串操作;
引用文件路径/名称以避免出现空格问题,因此使用usebackq
选项;
将tokens=*
替换为delims=
选项,以保留前导空格;为了避免由于默认的eol
选项而丢失以;
开头的行,我使用了看起来很奇怪的不带引号的选项字符串语法,因为这是没有delims
和eol
定义的唯一方法(!)同时(你不能写"delims= eol="
,因为这会将"
定义为eol
字符;"eol= delims="
将定义SPACE,而"eol=delims="
定义为d
);
redirected整个for
循环,所以不需要初始文件删除,性能也好很多,因为输出文件只需要打开和关闭一次,而不是每次迭代;
echo Text > "file.ext"
返回一个尾随 SPACE (实际上是 >
前面的那个);上述项目避免了这种情况;一般来说,使用反向重定向语法> "file.ext" echo Text
可以避免这种情况;
如果变量 VAR
为空,echo !VAR!
返回 ECHO is on|off.
;为了避免这种或其他意外输出,使用了看起来很奇怪但安全的语法echo(!VAR!
;
在启用延迟扩展时避免立即 (%
) 扩展以避免丢失 !
;
要保留原始文件中出现的空行,请将代码更改为:
@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
findstr
command 用于在输入文件的每一行前加上行号加冒号(/N
选项)。然后子字符串替换就完成了。最后,包括第一个 :
在内的所有内容,因此行号前缀被删除。
【讨论】:
"usebackq tokens=*
是一个糟糕的选择,因为它会去除前导空格和制表符。最好使用"usebackq delims="
。但是由于默认 EOL,:
仍然存在问题。最好的选择是看起来很糟糕的usebackq^ delims^=^ eol^=
,没有任何引号,因为它禁用了 DELIMS 和 EOL。
非常感谢 aschipfl。这行得通。虽然我昨天来了另一个问题 - 真实文件中有一些空行
对不起,我偶然按了 Enter - 完整的评论是:非常感谢 aschipfl。这行得通。虽然我昨天来了另一个问题 - 真实文件中有一些空行。看起来必须保留这些空行,否则文件将无用...也感谢 dbenham - 它也可以正常工作,即使以我的虫眼观点,我也无法理解那里的曲折。最好的,麦克。
要保持空行,看看this post...
非常感谢。但是有一个问题 - 空行充满了ECHO jest wyĄczone
,这意味着波兰语中的"ECHO is off"
。【参考方案2】:
在 .bat 文件脚本中替换短语非常容易。
powershell -NoLogo -NoProfile -Command ^
"Get-Content -Path '.\subfrase-in.txt' |" ^
"ForEach-Object $_ -replace 'WARNING: No video signal present!', 'Recognition suspended' "
【讨论】:
怀疑 OP 被否决。也许您说的是批处理文件但随后使用了 poweshell 的事实?是的,您可以批量包装 powershell,但为什么不单独使用 powershell? 我同意仅使用 PowerShell,但 OP 指定它必须“通过 CMD 批处理”完成。有些人不介意使用find.exe
、taskkill.exe
或net.exe
,但不愿使用powershell.exe
。这只是机器上的另一个命令。为什么不应该使用它?
我只是在考虑投反对票的原因。也许只是指定批量包装powershell命令。以上是关于包含特殊字符的 CMD 替换短语的主要内容,如果未能解决你的问题,请参考以下文章