通过批处理文件

时间:2015-08-04 20:34:30

标签: batch-file cmd

我尝试使用CMD或VBS删除包含txt文件中关键字的某些行。

我已阅读this,但情况并不相同。我想删除一系列行。

原始文本文件:

ABCDEFGXXX
ABCD
A
AE
AXXXLKGUSP
0000ASD
ASD

已处理的文字文件:

0000ASD
ASD

我想删除包含' XXX'的第一个实例的行范围和第二个。这个' XXX'只有两个例子。两个实例之间的行数是随机的,并且可能存在两个实例在同一行中的情况。 4个零也出现在' XXX'的第2个实例的行之后。请注意,它可能包含以下字符,因此如果您尝试处理,它可能会窒息。

---------------------编辑08/04/2015 7:41 PM ---------------- ------------------- " XXX"全部大写......文本文件可能包含下面的字符..但它在记事本中显示一行。 IDK他们是什么

PK
    ¨‘G_t¥0  8ˆ     XXXç¸[~-ÄWÀ¨Ì’gÝ

4 个答案:

答案 0 :(得分:1)

假设您已经提到VBS表示可以使用非纯语法语法解决方案,这里有一个PowerShell单行程序,您可以从.bat调用。

它以default系统编码读取文本文件,其他有用的值为UTF8Unicode
在2秒内处理100MB文件。

@echo off
set "string=XXX"
set "infile=input file.txt"
set "outfile=output file.txt"
set "encoding=default"

powershell -ExecutionPolicy bypass -c "$txt=(get-content '%infile%' -raw -encoding default); $i=$txt.indexof('%string%'); if($i -ge 0) { $j=$txt.indexof('%string%',$i+'%string%'.length); if($j -ge 0) {$k=$txt.indexof(\"`n\",$j); if($k -ge $j){$txt2=$txt.substring($k)} else {$txt2=''} $txt.substring(0,[math]::max(0,$txt.lastindexof(\"`n\",$i))) + $txt2 | out-file '%outfile%' -encoding %encoding%}}"
pause
    添加了
  • -ExecutionPolicy bypass以允许在非管理员用户帐户上执行powershell。
  • PowerShell 3.0及更高版本是必需的,默认情况下是Windows 7 SP1,8,10。

答案 1 :(得分:1)

这对于JREPL.BAT来说非常简单 - 一个基于纯脚本的实用程序(混合JScript /批处理),可以在XP以后的任何Windows机器上本机运行。关键特性是它支持多行正则表达式搜索和替换。

以下内容将覆盖原始文件:

jrepl "^.*?XXX[\s\S]*XXX.*\n?" "" /m /f "test.txt" /o -

如果您要创建新文件,只需为-选项指定文件名而不是/O

jrepl "^.*?XXX[\s\S]*XXX.*\n?" "" /m /f "input.txt" /o "output.txt"

或者您可以完全省略/O选项并将结果打印到屏幕(标准输出)

jrepl "^.*?XXX[\s\S]*XXX.*\n?" "" /m /f "input.txt"


如果您将命令放在批处理脚本中,请使用call jrepl ...


编辑:这是一个纯批处理解决方案。通常我放弃使用批处理进行文本处理,因为强大的解决方案需要过多的精神错乱。下面的代码非常强大和优化,但即使如此,仍然有以下限制:

  • 行数限于< 8k
  • 搜索的关键字不能以*开头,且不能包含=!"
  • 搜索忽略大小写,没有选项使其区分大小写

可能还有一些我错过了。

但代码确实保留了空行,并且不会阻塞内容中的!。 (处理这些可能性是造成复杂性的原因)

@echo off
setlocal disableDelayedExpansion

set "in=input.txt"
set "out=output.txt"
set "find=XXX"

set "cnt=0"
>"%out%" (
  for /f "delims=" %%A in ('findstr /n "^" "%in%"') do (
    set "ln=%%A"
    setlocal enableDelayedExpansion
    set "ln=!ln:*:=!"
    if defined ln if !cnt! equ 0 (
      set "test=!ln:*%find%=!"
      if !test! neq !ln! set "cnt=1"
    ) else set "test=!ln!"
    if !cnt! neq 1 echo(!ln!
    if defined test if !cnt! neq 2 if "!test:%find%=!" neq "!test!" set "cnt=2"
    for %%N in (!cnt!) do endlocal&set "cnt=%%N"
  )
)

答案 2 :(得分:1)

这是一个纯粹的CMD实现:

@echo off

rem DEFINITIONS:
set "KEYWD=XXX"
set "INFILE=original.txt"
set "OUTFILE=modified.txt"

setlocal EnableExtensions EnableDelayedExpansion

rem GET_LINE_NUMBERS:
set "NUMONE="
set "NUMTWO="
for /F %%F in ('findstr /N /L /C:"%KEYWD%" "%INFILE%"') do (
  for /F "delims=:" %%N in ("%%F") do (
    if not defined NUMONE (
      set "NUMONE=%%N"
    ) else (
      set "NUMTWO=%%N"
    )
  )
)
if not defined NUMTWO set "NUMTWO=%NUMONE%"

rem RETURN_BEFORE_BLOCK:
set /A "COUNT=0"
rem.> "%OUTFILE%"
for /F "delims=" %%L in ('findstr /N /R "^" "%INFILE%"') do (
  set /A "COUNT+=1"
  if !COUNT! geq !NUMONE! (
    goto :NEXT
  ) else (
    setlocal DisableDelayedExpansion
    set "LINE=%%L"
    setlocal EnableDelayedExpansion
    echo(!LINE:*:=!
    endlocal
    endlocal
  ) >> "%OUTFILE%"
)

rem RETURN_AFTER_BLOCK:
:NEXT
if defined NUMTWO set "SKIP=skip=!NUMTWO!"
for /F "%SKIP% delims=" %%L in ('findstr /N /R "^" "%INFILE%"') do (
  setlocal DisableDelayedExpansion
  set "LINE=%%L"
  setlocal EnableDelayedExpansion
  echo(!LINE:*:=!
  endlocal
  endlocal
) >> "%OUTFILE%"

endlocal

代码由四部分组成(请参阅备注rem):

  • 定义:在这里你需要定义搜索关键字,输入和输出文件;
  • GET_LINE_NUMBERS:此部分搜索给定关键字的两次出现的行号;生成的行号存储在相应的变量NUMONENUMTWO中;如果只找到一行(a)匹配,NUMTWO设置为NUMONE;如果未找到匹配项,则两个变量都保持为空;
  • RETURN_BEFORE_BLOCK:此处输出所有内容但不包括第一个关键字匹配的行;它依赖于goto打破任何正在进行的for循环上下文的事实;
  • RETURN_AFTER_BLOCK:在此部分中,返回第二个关键字匹配后的每一行并将其附加到上一部分的输出中;这里for /F选项参数skip是动态构建的;

答案 3 :(得分:0)

这是另一个JScript / Batch混合解决方案。

假设文本文件位于data.txt中,我们可以调用替换脚本:

cscript //nologo j.js .*XXX.*\n[\s\S]*?.*\n*XXX.* "" < data.txt

j.js是使用Microsoft JScript编写的支持脚本:

var txt = WScript.StdIn.ReadAll();
var pattern = new RegExp( WScript.Arguments.Item(0), "g" );
var newvalue = WScript.Arguments.Item(1);
txt = txt.replace( pattern, newvalue );
WScript.StdOut.Write( txt );

j.js脚本的高尔夫优化版本为:

WScript.StdOut.Write(WScript.StdIn.ReadAll().replace(new RegExp(WScript.Arguments.Item(0),"g"),WScript.Arguments.Item(1)));

通常,j.js的用法是:

cscript //nologo j.js pattern_regular_expression new_value < input.dat > output.dat

input.dat指的是输入文本/数据文件。如果省略< input.dat,则输入将从用户输入中获取。 output.dat指的是输出文本/数据文件。如果省略> output.dat,则输出将显示在控制台上。