bat文件替换文本文件中的字符串

时间:2021-02-14 22:26:20

This question has been asked a lot on *, but I can't seem to be able to make it work. Any hints appreciated. Here is a text file (extension .mpl) containing offending text that needs to be removed:

这个问题在*上被问了很多,但是我似乎不能让它发挥作用。任何暗示感激。这是一个文本文件(扩展名.mpl),包含需要删除的违规文本:

plotsetup('ps', 'plotoutput = "plotfile.eps"', 'plotoptions' = "color=rgb,landscape,noborder");
print(PLOT3D(MESH(Array(1..60, 1..60, 1..3, [[[.85840734641021,0.,-0.],
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],[.857971665313419,.0917163905694189,-.16720239349226],
... more like that ...
[.858407346410207,-3.25992468340355e-015,5.96532373555817e-015]]], datatype = float[8], order = C_order)),SHADING(ZHUE),STYLE(PATCHNOGRID),TRANSPARENCY(.3),LIGHTMODEL(LIGHT_4),ORIENTATION(35.,135.),SCALING(CONSTRAINED),AXESSTYLE(NORMAL)));

I want to remove every instance of:

我要删除每个实例:

[HFloat(undefined),HFloat(undefined),HFloat(undefined)],

and there are thousands such instances!. Note: the square brackets and the comma are to be removed. There is no space, so I have pages and pages of:

有成千上万这样的例子!注意:方括号和逗号要删除。没有空间,所以我有很多页:

[HFloat(undefined),HFloat(undefined),HFloat(undefined)],   
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],   
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],

I won't list here all my failed attempts. Below is the closest I've come:

我不会在这里列出我所有失败的尝试。下面是我最接近的一次:

@echo off

SetLocal 
cd /d %~dp0

if exist testCleaned.mpl del testCleaned.mpl

SetLocal EnableDelayedExpansion

Set OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],
Set NewString=

pause

FOR /F "tokens=* delims= " %%I IN (test.mpl) DO (
    set str=%%I
    set str=!str:OldString=NewString!
    echo !str! >> testCleaned.mpl
    endlocal
)

EndLocal

The above was strung together, as it were, from pieces of code found on the web, especially at *, e.g. Problem with search and replace batch file

上面的代码实际上是从web上找到的代码片段串在一起的,特别是在*上,例如搜索和替换批处理文件的问题

What it does is produce a truncated file, as follows:

它所做的是生成一个被截断的文件,如下所示:

plotsetup('ps', 'plotoutput = "plotfile.eps"', 'plotoptions' = "color=rgb,landscape,noborder"); 
!str! 

Please don't hesitate to request clarifications. Apologies if you feel that this question has already been answered. I would very much appreciate if you would copy-paste the relevant code for me, as I have tried for several hours.

请随时要求澄清。如果你觉得这个问题已经被回答了,请道歉。如果你能帮我复制相关的代码,我会非常感激,因为我已经试了几个小时了。

Bonus: can this automatic naming be made to work? "%%~nICleaned.mpl"

附加条件:这个自动命名可以工作吗?“% % ~ nICleaned.mpl”

4 个解决方案

#1


6  

The biggest problem with your existing code is the SetLocal enableDelayedExpansion is missplaced - it should be within the loop after set str=%%I.

现有代码最大的问题是SetLocal enableDelayedExpansion出现了错误——它应该在set str=% I之后的循环中。

Other problems:

其他问题:

  • will strip lines beginning with ;
  • 将带线开始;
  • will strip leading spaces from each line
  • 是否会从每行带出领先的空间?
  • will strip blank (empty) lines
  • 将删除空(空)行吗
  • will print ECHO is off if any lines becomes empty or contains only spaces after substitution
  • 如果任何行变为空,或者在替换后只包含空格,打印ECHO会关闭吗
  • will add extra space at end of each line (didn't notice this until I read jeb's answer)
  • 将在每行末尾添加额外的空格(直到我读到jeb的答案时才注意到这一点)

Optimization issue - using >> can be relatively slow. It is faster to enclose the whole loop in () and then use >

优化问题——使用>>可能会比较慢。将整个循环封装在()中,然后使用>会更快

Below is about the best you can do with Windows batch. I auto named the output as requested, doing one better - It automatically preserves the extension of the original name.

下面是有关Windows批处理的最佳示例。我按要求自动命名输出,做得更好——它自动保留原名称的扩展名。

@echo off
SetLocal
cd /d %~dp0
Set "OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],"
Set "NewString="
set file="test.mpl"
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF"
pause
(
  for /f "skip=2 delims=" %%a in ('find /n /v "" %file%') do (
    set "ln=%%a"
    setlocal enableDelayedExpansion
    set "ln=!ln:*]=!"
    if defined ln set "ln=!ln:%OldString%=%NewString%!"
    echo(!ln!
    endlocal
  )
)>%outFile%

Known limitations

已知的限制

  • limited to slightly under 8k per line, both before and after substitution
  • 在换人前后,每行限制在8k以下
  • search string cannot include = or !, nor can it start with * or ~
  • 搜索字符串不能包含=或!,也不能以*或~开头
  • replacement string cannot include !
  • 替换字符串不能包含!
  • search part of search and replace is case insensitive
  • 搜索和替换部分是不区分大小写的
  • last line will always end with newline <CR><LF> even if original did not
  • 最后一行总是以换行符 结束,即使原行没有

All but the first limitation could be eliminated, but it would require a lot of code, and would be horrifically slow. The solution would require a character by character search of each line. The last limitation would require some awkward test to determine if the last line was newline terminated, and then last line would have to be printed using <nul SET /P "ln=!ln!" trick if no newline wanted.

除了第一个限制之外,其他所有限制都可以被消除,但这需要大量的代码,而且速度会非常慢。解决方案需要一个字符通过字符搜索每一行。最后一个限制将需要一些笨拙的测试来确定最后一行是否终止了换行,然后如果不需要换行,则必须使用

Interesting feature (or limitation, depending on perspective)

有趣的特性(或限制,取决于视角)

  • Unix style files ending lines with <LF> will be converted to Windows style with lines ending with <CR><LF>
  • 结尾的Unix风格文件将转换为Windows风格,以 结尾的行

There are other solutions using batch that are significantly faster, but they all have more limitations.

使用批处理的其他解决方案要快得多,但它们都有更多的局限性。

Update - I've posted a new pure batch solution that is able to do case sensitive searches and has no restrictions on search or replacement string content. It does have more restrictions on line length, trailing control characters, and line format. Performance is not bad, especially if the number of replacements is low. http://www.dostips.com/forum/viewtopic.php?f=3&t=2710

更新——我发布了一个新的纯批处理解决方案,可以进行区分大小写的搜索,并且对搜索或替换字符串内容没有限制。它对行长度、跟踪控制字符和行格式有更多的限制。性能还不错,特别是当替换的数量较低时。http://www.dostips.com/forum/viewtopic.php?f=3&t=2710

Addendum

齿顶高

Based on comments below, a batch solution will not work for this particular problem because of line length limitation.

基于下面的注释,由于行长度的限制,批解决方案不会对这个特定的问题起作用。

But this code is a good basis for a batch based search and replace utility, as long as you are willing to put up with the limitations and relatively poor performance of batch.

但此代码是基于批处理的搜索和替换实用程序的良好基础,只要您愿意忍受批处理的局限性和相对较差的性能。

There are much better text processing tools available, though they are not standard with Windows. My favorite is sed within the GNU Utilities for Win32 package. The utilities are free, and do not require any installation.

有更好的文本处理工具可用,尽管它们不是Windows的标准。我最喜欢的是在GNU工具中使用Win32包。这些实用程序是免费的,不需要任何安装。

Here is a sed solution for Windows using GNU utilities

下面是一个使用GNU实用程序的Windows sed解决方案

@echo off
setlocal
cd /d %~dp0
Set "OldString=\[HFloat(undefined),HFloat(undefined),HFloat(undefined)\],"
Set "NewString="
set file="test.mpl"
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF"
pause
sed -e"s/%OldString%/%NewString%/g" <%file% >%outfile%


Update 2013-02-19

更新2013-02-19

sed may not be an option if you work at a site that has rules forbidding the installation of executables downloaded from the web.

如果您在一个禁止安装从web下载的可执行文件的网站工作,那么sed可能不是一个选项。

JScript has good regular expression handling, and it is standard on all modern Windows platforms, including XP. It is a good choice for performing search and replace operations on Windows platforms.

JScript有很好的正则表达式处理,它是所有现代Windows平台的标准,包括XP。对于在Windows平台上进行搜索和替换操作,这是一个很好的选择。

I have written a hybrid JScript/Batch search and replace script (REPL.BAT) that is easy to call from a batch script. A small amount of code gives a lot of powerful features; not as powerful as sed, but more than enough to handle this task, as well as many others. It is also quite fast, much faster than any pure batch solution. It also does not have any inherent line length limitations.

我编写了一个混合的JScript/批处理搜索和替换脚本(REPL.BAT),很容易从批处理脚本调用。少量的代码提供了很多强大的特性;虽然不如sed强大,但足以处理这个任务,以及其他许多任务。它也非常快,比任何纯批解决方案快得多。它也没有任何固有的线长度限制。

Here is a batch script that uses my REPL.BAT utility to accomplish the task.

这是一个使用我的REPL的批处理脚本。BAT实用工具来完成任务。

@echo off
setlocal
cd /d %~dp0
Set "OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],"
Set "NewString="
set file="test.txt"
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF"
pause
call repl OldString NewString le <%file% >%outfile%

I use the L option to specify a literal search string instead of a regular expression, and the E option to pass the search and replace strings via environment variables by name, instead of using string literals on the command line.

我使用L选项指定文字搜索字符串而不是正则表达式,使用E选项通过环境变量名称传递搜索并替换字符串,而不是在命令行上使用字符串文字。

Here is the REPL.BAT utility script that the above code calls. Full documentation is encluded within the script.

这是REPL。上述代码调用的BAT实用脚本。脚本中包含完整的文档。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::************ Documentation ***********
:::
:::REPL  Search  Replace  [Options  [SourceVar]]
:::REPL  /?
:::
:::  Performs a global search and replace operation on each line of input from
:::  stdin and prints the result to stdout.
:::
:::  Each parameter may be optionally enclosed by double quotes. The double
:::  quotes are not considered part of the argument. The quotes are required
:::  if the parameter contains a batch token delimiter like space, tab, comma,
:::  semicolon. The quotes should also be used if the argument contains a
:::  batch special character like &, |, etc. so that the special character
:::  does not need to be escaped with ^.
:::
:::  If called with a single argument of /? then prints help documentation
:::  to stdout.
:::
:::  Search  - By default this is a case sensitive JScript (ECMA) regular
:::            expression expressed as a string.
:::
:::            JScript syntax documentation is available at
:::            http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
:::  Replace - By default this is the string to be used as a replacement for
:::            each found search expression. Full support is provided for
:::            substituion patterns available to the JScript replace method.
:::            A $ literal can be escaped as $$. An empty replacement string
:::            must be represented as "".
:::
:::            Replace substitution pattern syntax is documented at
:::            http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
:::  Options - An optional string of characters used to alter the behavior
:::            of REPL. The option characters are case insensitive, and may
:::            appear in any order.
:::
:::            I - Makes the search case-insensitive.
:::
:::            L - The Search is treated as a string literal instead of a
:::                regular expression. Also, all $ found in Replace are
:::                treated as $ literals.
:::
:::            E - Search and Replace represent the name of environment
:::                variables that contain the respective values. An undefined
:::                variable is treated as an empty string.
:::
:::            M - Multi-line mode. The entire contents of stdin is read and
:::                processed in one pass instead of line by line. ^ anchors
:::                the beginning of a line and $ anchors the end of a line.
:::
:::            X - Enables extended substitution pattern syntax with support
:::                for the following escape sequences:
:::
:::                \\     -  Backslash
:::                \b     -  Backspace
:::                \f     -  Formfeed
:::                \n     -  Newline
:::                \r     -  Carriage Return
:::                \t     -  Horizontal Tab
:::                \v     -  Vertical Tab
:::                \xnn   -  Ascii (Latin 1) character expressed as 2 hex digits
:::                \unnnn -  Unicode character expressed as 4 hex digits
:::
:::                Escape sequences are supported even when the L option is used.
:::
:::            S - The source is read from an environment variable instead of
:::                from stdin. The name of the source environment variable is
:::                specified in the next argument after the option string.
:::

::************ Batch portion ***********
@echo off
if .%2 equ . (
  if "%~1" equ "/?" (
    findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
    exit /b 0
  ) else (
    call :err "Insufficient arguments"
    exit /b 1
  )
)
echo(%~3|findstr /i "[^SMILEX]" >nul && (
  call :err "Invalid option(s)"
  exit /b 1
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0

:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b

************* JScript portion **********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) {
  options+=args.Item(2).toLowerCase();
}
var multi=(options.indexOf("m")>=0);
var srcVar=(options.indexOf("s")>=0);
if (srcVar) {
  options=options.replace(/s/g,"");
}
if (options.indexOf("e")>=0) {
  options=options.replace(/e/g,"");
  search=env(search);
  replace=env(replace);
}
if (options.indexOf("l")>=0) {
  options=options.replace(/l/g,"");
  search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
  replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("x")>=0) {
  options=options.replace(/x/g,"");
  replace=replace.replace(/\\\\/g,"\\B");
  replace=replace.replace(/\\b/g,"\b");
  replace=replace.replace(/\\f/g,"\f");
  replace=replace.replace(/\\n/g,"\n");
  replace=replace.replace(/\\r/g,"\r");
  replace=replace.replace(/\\t/g,"\t");
  replace=replace.replace(/\\v/g,"\v");
  replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
    function($0,$1,$2){
      return String.fromCharCode(parseInt("0x"+$0.substring(2)));
    }
  );
  replace=replace.replace(/\\B/g,"\\");
}
var search=new RegExp(search,options);

if (srcVar) {
  WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
} else {
  while (!WScript.StdIn.AtEndOfStream) {
    if (multi) {
      WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
    } else {
      WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
    }
  }
}

#2


2  

The Batch file below have the same restrictions of previous solutions on characters that can be processed; these restrictions are inherent to all Batch language programs. However, this program should run faster if the file is large and the lines to replace are not too much. Lines with no replacement string are not processed, but directly copied to the output file.

下面的批处理文件对可以处理的字符具有与以前解决方案相同的限制;这些限制是所有批处理语言程序固有的。但是,如果文件很大并且要替换的行不多,那么这个程序应该运行得更快。没有替换字符串的行不会被处理,而是直接复制到输出文件。

@echo off
setlocal EnableDelayedExpansion
set "oldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],"
set "newString="
findstr /N ^^ inFile.mpl > numberedFile.tmp
find /C ":" < numberedFile.tmp > lastLine.tmp
set /P lastLine=<lastLine.tmp
del lastLine.tmp
call :ProcessLines < numberedFile.tmp > outFile.mpl
del numberedFile.tmp
goto :EOF

:ProcessLines
set lastProcessedLine=0
for /F "delims=:" %%a in ('findstr /N /C:"%oldString%" inFile.mpl') do (
    call :copyUpToLine %%a
    echo(!line:%oldString%=%newString%!
)
set /A linesToCopy=lastLine-lastProcessedLine
for /L %%i in (1,1,%linesToCopy%) do (
    set /P line=
    echo(!line:*:=!
)
exit /B

:copyUpToLine number
set /A linesToCopy=%1-lastProcessedLine-1
for /L %%i in (1,1,%linesToCopy%) do (
    set /P line=
    echo(!line:*:=!
)
set /P line=
set line=!line:*:=!
set lastProcessedLine=%1
exit /B

I would appreciate if you may run a timing test on this an other solutions and post the results.

如果您能在其他解决方案上运行时间测试并发布结果,我将不胜感激。

EDIT: I changed the set /A lastProcessedLine+=linesToCopy+1 line for the equivalent, but faster set lastProcessedLine=%1.

编辑:我更改了set /A lastProcessedLine+=linesToCopy+1行,但是更快的set lastprocesline =%1。

#3


0  

I'm no expert on batch files, so I can't offer a direct solution to your problem.

我不是批处理文件的专家,所以我不能直接解决你的问题。

However, to solve your problem, it might be simpler to use an alternative to batch files.

但是,为了解决您的问题,使用批处理文件的替代方法可能更简单。

For example, I'd recommend using http://www.csscript.net/ (if you know C#). This tool will allow you to run C# files like batch files, but giving you the power to write your script using C#, instead of horrible batch file syntax :)

例如,我建议使用http://www.csscript.net/(如果您知道c#)。这个工具将允许您运行c#文件,比如批处理文件,但是可以让您使用c#编写脚本,而不是使用糟糕的批处理文件语法:)

Another alternative would be python, if you know python.

另一种选择是python,如果您知道python。

But I guess the point is, that this kind of task may be easier in another programming language.

但我想关键是,这种任务在另一种编程语言中可能更容易。

#4


0  

You defined delims=<space>, that's a bad idea if you want to preserve your lines, as it splits after the first space.
You should change this to FOR /F "tokens=* delims=" ....

你定义了delims= ,如果你想保留你的行,这不是一个好主意,因为它在第一个空格后分裂。你应该改变这种/ F”令牌= * delims = " ....

Your echo !str! >> testCleaned.mpl will always append one extra space to each line, better use echo(!str!>>testCleaned.mpl.

你的回音! str !> > testCleaned。mpl总是会在每行增加一个额外的空间,最好使用echo(!str!>>test clean .mpl)。

You will also lose all empty lines, and all exclamation marks in all lines.

您还将丢失所有空行,以及所有行中的所有感叹号。

You could also try the code of Improved BatchSubstitute.bat

您也可以尝试改进batchreplace .bat的代码

#1


6  

The biggest problem with your existing code is the SetLocal enableDelayedExpansion is missplaced - it should be within the loop after set str=%%I.

现有代码最大的问题是SetLocal enableDelayedExpansion出现了错误——它应该在set str=% I之后的循环中。

Other problems:

其他问题:

  • will strip lines beginning with ;
  • 将带线开始;
  • will strip leading spaces from each line
  • 是否会从每行带出领先的空间?
  • will strip blank (empty) lines
  • 将删除空(空)行吗
  • will print ECHO is off if any lines becomes empty or contains only spaces after substitution
  • 如果任何行变为空,或者在替换后只包含空格,打印ECHO会关闭吗
  • will add extra space at end of each line (didn't notice this until I read jeb's answer)
  • 将在每行末尾添加额外的空格(直到我读到jeb的答案时才注意到这一点)

Optimization issue - using >> can be relatively slow. It is faster to enclose the whole loop in () and then use >

优化问题——使用>>可能会比较慢。将整个循环封装在()中,然后使用>会更快

Below is about the best you can do with Windows batch. I auto named the output as requested, doing one better - It automatically preserves the extension of the original name.

下面是有关Windows批处理的最佳示例。我按要求自动命名输出,做得更好——它自动保留原名称的扩展名。

@echo off
SetLocal
cd /d %~dp0
Set "OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],"
Set "NewString="
set file="test.mpl"
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF"
pause
(
  for /f "skip=2 delims=" %%a in ('find /n /v "" %file%') do (
    set "ln=%%a"
    setlocal enableDelayedExpansion
    set "ln=!ln:*]=!"
    if defined ln set "ln=!ln:%OldString%=%NewString%!"
    echo(!ln!
    endlocal
  )
)>%outFile%

Known limitations

已知的限制

  • limited to slightly under 8k per line, both before and after substitution
  • 在换人前后,每行限制在8k以下
  • search string cannot include = or !, nor can it start with * or ~
  • 搜索字符串不能包含=或!,也不能以*或~开头
  • replacement string cannot include !
  • 替换字符串不能包含!
  • search part of search and replace is case insensitive
  • 搜索和替换部分是不区分大小写的
  • last line will always end with newline <CR><LF> even if original did not
  • 最后一行总是以换行符 结束,即使原行没有

All but the first limitation could be eliminated, but it would require a lot of code, and would be horrifically slow. The solution would require a character by character search of each line. The last limitation would require some awkward test to determine if the last line was newline terminated, and then last line would have to be printed using <nul SET /P "ln=!ln!" trick if no newline wanted.

除了第一个限制之外,其他所有限制都可以被消除,但这需要大量的代码,而且速度会非常慢。解决方案需要一个字符通过字符搜索每一行。最后一个限制将需要一些笨拙的测试来确定最后一行是否终止了换行,然后如果不需要换行,则必须使用

Interesting feature (or limitation, depending on perspective)

有趣的特性(或限制,取决于视角)

  • Unix style files ending lines with <LF> will be converted to Windows style with lines ending with <CR><LF>
  • 结尾的Unix风格文件将转换为Windows风格,以 结尾的行

There are other solutions using batch that are significantly faster, but they all have more limitations.

使用批处理的其他解决方案要快得多,但它们都有更多的局限性。

Update - I've posted a new pure batch solution that is able to do case sensitive searches and has no restrictions on search or replacement string content. It does have more restrictions on line length, trailing control characters, and line format. Performance is not bad, especially if the number of replacements is low. http://www.dostips.com/forum/viewtopic.php?f=3&t=2710

更新——我发布了一个新的纯批处理解决方案,可以进行区分大小写的搜索,并且对搜索或替换字符串内容没有限制。它对行长度、跟踪控制字符和行格式有更多的限制。性能还不错,特别是当替换的数量较低时。http://www.dostips.com/forum/viewtopic.php?f=3&t=2710

Addendum

齿顶高

Based on comments below, a batch solution will not work for this particular problem because of line length limitation.

基于下面的注释,由于行长度的限制,批解决方案不会对这个特定的问题起作用。

But this code is a good basis for a batch based search and replace utility, as long as you are willing to put up with the limitations and relatively poor performance of batch.

但此代码是基于批处理的搜索和替换实用程序的良好基础,只要您愿意忍受批处理的局限性和相对较差的性能。

There are much better text processing tools available, though they are not standard with Windows. My favorite is sed within the GNU Utilities for Win32 package. The utilities are free, and do not require any installation.

有更好的文本处理工具可用,尽管它们不是Windows的标准。我最喜欢的是在GNU工具中使用Win32包。这些实用程序是免费的,不需要任何安装。

Here is a sed solution for Windows using GNU utilities

下面是一个使用GNU实用程序的Windows sed解决方案

@echo off
setlocal
cd /d %~dp0
Set "OldString=\[HFloat(undefined),HFloat(undefined),HFloat(undefined)\],"
Set "NewString="
set file="test.mpl"
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF"
pause
sed -e"s/%OldString%/%NewString%/g" <%file% >%outfile%


Update 2013-02-19

更新2013-02-19

sed may not be an option if you work at a site that has rules forbidding the installation of executables downloaded from the web.

如果您在一个禁止安装从web下载的可执行文件的网站工作,那么sed可能不是一个选项。

JScript has good regular expression handling, and it is standard on all modern Windows platforms, including XP. It is a good choice for performing search and replace operations on Windows platforms.

JScript有很好的正则表达式处理,它是所有现代Windows平台的标准,包括XP。对于在Windows平台上进行搜索和替换操作,这是一个很好的选择。

I have written a hybrid JScript/Batch search and replace script (REPL.BAT) that is easy to call from a batch script. A small amount of code gives a lot of powerful features; not as powerful as sed, but more than enough to handle this task, as well as many others. It is also quite fast, much faster than any pure batch solution. It also does not have any inherent line length limitations.

我编写了一个混合的JScript/批处理搜索和替换脚本(REPL.BAT),很容易从批处理脚本调用。少量的代码提供了很多强大的特性;虽然不如sed强大,但足以处理这个任务,以及其他许多任务。它也非常快,比任何纯批解决方案快得多。它也没有任何固有的线长度限制。

Here is a batch script that uses my REPL.BAT utility to accomplish the task.

这是一个使用我的REPL的批处理脚本。BAT实用工具来完成任务。

@echo off
setlocal
cd /d %~dp0
Set "OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],"
Set "NewString="
set file="test.txt"
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF"
pause
call repl OldString NewString le <%file% >%outfile%

I use the L option to specify a literal search string instead of a regular expression, and the E option to pass the search and replace strings via environment variables by name, instead of using string literals on the command line.

我使用L选项指定文字搜索字符串而不是正则表达式,使用E选项通过环境变量名称传递搜索并替换字符串,而不是在命令行上使用字符串文字。

Here is the REPL.BAT utility script that the above code calls. Full documentation is encluded within the script.

这是REPL。上述代码调用的BAT实用脚本。脚本中包含完整的文档。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::************ Documentation ***********
:::
:::REPL  Search  Replace  [Options  [SourceVar]]
:::REPL  /?
:::
:::  Performs a global search and replace operation on each line of input from
:::  stdin and prints the result to stdout.
:::
:::  Each parameter may be optionally enclosed by double quotes. The double
:::  quotes are not considered part of the argument. The quotes are required
:::  if the parameter contains a batch token delimiter like space, tab, comma,
:::  semicolon. The quotes should also be used if the argument contains a
:::  batch special character like &, |, etc. so that the special character
:::  does not need to be escaped with ^.
:::
:::  If called with a single argument of /? then prints help documentation
:::  to stdout.
:::
:::  Search  - By default this is a case sensitive JScript (ECMA) regular
:::            expression expressed as a string.
:::
:::            JScript syntax documentation is available at
:::            http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
:::  Replace - By default this is the string to be used as a replacement for
:::            each found search expression. Full support is provided for
:::            substituion patterns available to the JScript replace method.
:::            A $ literal can be escaped as $$. An empty replacement string
:::            must be represented as "".
:::
:::            Replace substitution pattern syntax is documented at
:::            http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
:::  Options - An optional string of characters used to alter the behavior
:::            of REPL. The option characters are case insensitive, and may
:::            appear in any order.
:::
:::            I - Makes the search case-insensitive.
:::
:::            L - The Search is treated as a string literal instead of a
:::                regular expression. Also, all $ found in Replace are
:::                treated as $ literals.
:::
:::            E - Search and Replace represent the name of environment
:::                variables that contain the respective values. An undefined
:::                variable is treated as an empty string.
:::
:::            M - Multi-line mode. The entire contents of stdin is read and
:::                processed in one pass instead of line by line. ^ anchors
:::                the beginning of a line and $ anchors the end of a line.
:::
:::            X - Enables extended substitution pattern syntax with support
:::                for the following escape sequences:
:::
:::                \\     -  Backslash
:::                \b     -  Backspace
:::                \f     -  Formfeed
:::                \n     -  Newline
:::                \r     -  Carriage Return
:::                \t     -  Horizontal Tab
:::                \v     -  Vertical Tab
:::                \xnn   -  Ascii (Latin 1) character expressed as 2 hex digits
:::                \unnnn -  Unicode character expressed as 4 hex digits
:::
:::                Escape sequences are supported even when the L option is used.
:::
:::            S - The source is read from an environment variable instead of
:::                from stdin. The name of the source environment variable is
:::                specified in the next argument after the option string.
:::

::************ Batch portion ***********
@echo off
if .%2 equ . (
  if "%~1" equ "/?" (
    findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
    exit /b 0
  ) else (
    call :err "Insufficient arguments"
    exit /b 1
  )
)
echo(%~3|findstr /i "[^SMILEX]" >nul && (
  call :err "Invalid option(s)"
  exit /b 1
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0

:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b

************* JScript portion **********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) {
  options+=args.Item(2).toLowerCase();
}
var multi=(options.indexOf("m")>=0);
var srcVar=(options.indexOf("s")>=0);
if (srcVar) {
  options=options.replace(/s/g,"");
}
if (options.indexOf("e")>=0) {
  options=options.replace(/e/g,"");
  search=env(search);
  replace=env(replace);
}
if (options.indexOf("l")>=0) {
  options=options.replace(/l/g,"");
  search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
  replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("x")>=0) {
  options=options.replace(/x/g,"");
  replace=replace.replace(/\\\\/g,"\\B");
  replace=replace.replace(/\\b/g,"\b");
  replace=replace.replace(/\\f/g,"\f");
  replace=replace.replace(/\\n/g,"\n");
  replace=replace.replace(/\\r/g,"\r");
  replace=replace.replace(/\\t/g,"\t");
  replace=replace.replace(/\\v/g,"\v");
  replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
    function($0,$1,$2){
      return String.fromCharCode(parseInt("0x"+$0.substring(2)));
    }
  );
  replace=replace.replace(/\\B/g,"\\");
}
var search=new RegExp(search,options);

if (srcVar) {
  WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
} else {
  while (!WScript.StdIn.AtEndOfStream) {
    if (multi) {
      WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
    } else {
      WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
    }
  }
}

#2


2  

The Batch file below have the same restrictions of previous solutions on characters that can be processed; these restrictions are inherent to all Batch language programs. However, this program should run faster if the file is large and the lines to replace are not too much. Lines with no replacement string are not processed, but directly copied to the output file.

下面的批处理文件对可以处理的字符具有与以前解决方案相同的限制;这些限制是所有批处理语言程序固有的。但是,如果文件很大并且要替换的行不多,那么这个程序应该运行得更快。没有替换字符串的行不会被处理,而是直接复制到输出文件。

@echo off
setlocal EnableDelayedExpansion
set "oldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)],"
set "newString="
findstr /N ^^ inFile.mpl > numberedFile.tmp
find /C ":" < numberedFile.tmp > lastLine.tmp
set /P lastLine=<lastLine.tmp
del lastLine.tmp
call :ProcessLines < numberedFile.tmp > outFile.mpl
del numberedFile.tmp
goto :EOF

:ProcessLines
set lastProcessedLine=0
for /F "delims=:" %%a in ('findstr /N /C:"%oldString%" inFile.mpl') do (
    call :copyUpToLine %%a
    echo(!line:%oldString%=%newString%!
)
set /A linesToCopy=lastLine-lastProcessedLine
for /L %%i in (1,1,%linesToCopy%) do (
    set /P line=
    echo(!line:*:=!
)
exit /B

:copyUpToLine number
set /A linesToCopy=%1-lastProcessedLine-1
for /L %%i in (1,1,%linesToCopy%) do (
    set /P line=
    echo(!line:*:=!
)
set /P line=
set line=!line:*:=!
set lastProcessedLine=%1
exit /B

I would appreciate if you may run a timing test on this an other solutions and post the results.

如果您能在其他解决方案上运行时间测试并发布结果,我将不胜感激。

EDIT: I changed the set /A lastProcessedLine+=linesToCopy+1 line for the equivalent, but faster set lastProcessedLine=%1.

编辑:我更改了set /A lastProcessedLine+=linesToCopy+1行,但是更快的set lastprocesline =%1。

#3


0  

I'm no expert on batch files, so I can't offer a direct solution to your problem.

我不是批处理文件的专家,所以我不能直接解决你的问题。

However, to solve your problem, it might be simpler to use an alternative to batch files.

但是,为了解决您的问题,使用批处理文件的替代方法可能更简单。

For example, I'd recommend using http://www.csscript.net/ (if you know C#). This tool will allow you to run C# files like batch files, but giving you the power to write your script using C#, instead of horrible batch file syntax :)

例如,我建议使用http://www.csscript.net/(如果您知道c#)。这个工具将允许您运行c#文件,比如批处理文件,但是可以让您使用c#编写脚本,而不是使用糟糕的批处理文件语法:)

Another alternative would be python, if you know python.

另一种选择是python,如果您知道python。

But I guess the point is, that this kind of task may be easier in another programming language.

但我想关键是,这种任务在另一种编程语言中可能更容易。

#4


0  

You defined delims=<space>, that's a bad idea if you want to preserve your lines, as it splits after the first space.
You should change this to FOR /F "tokens=* delims=" ....

你定义了delims= ,如果你想保留你的行,这不是一个好主意,因为它在第一个空格后分裂。你应该改变这种/ F”令牌= * delims = " ....

Your echo !str! >> testCleaned.mpl will always append one extra space to each line, better use echo(!str!>>testCleaned.mpl.

你的回音! str !> > testCleaned。mpl总是会在每行增加一个额外的空间,最好使用echo(!str!>>test clean .mpl)。

You will also lose all empty lines, and all exclamation marks in all lines.

您还将丢失所有空行,以及所有行中的所有感叹号。

You could also try the code of Improved BatchSubstitute.bat

您也可以尝试改进batchreplace .bat的代码