Bat文件在.txt文件中查找某些文本

时间:2012-08-27 23:18:55

标签: file search batch-file filter find

只是想知道批处理文件中是否有任何代码可以在.txt文件中找到某个文本或单词。

例如:

  1. 快速的棕色狐狸在懒狗身上跳跃\标记{1}
  2. 快速\标记{10}棕色狐狸跳过懒狗
  3. 快速的棕色狐狸跳过懒惰的\ mark {100}狗
  4. 快速的棕色狐狸跳过懒狗\标记{1000}
  5. \ mark {1}快速的棕色狐狸跳过懒狗
  6. 快速的棕色狐狸跳过懒狗\标记{100}
  7. 快速的棕色狐狸\标记{30}跳过懒狗
  8. 从上面的示例中可以看出,我想搜索“\ mark {Number here}”这个词,并且如果有可能的话,当出现相同的单词时,例如第一行和第五行,它只显示第一行的“\ mark {1}”并忽略第五行中的相同单词

    所以结果将打印在一个txt文件中:

    1. \标记{1}
    2. \标记{10}
    3. \标记{100}
    4. \ {标记1000}
    5. \ {标记30}

2 个答案:

答案 0 :(得分:1)

如果您下载像sed for Windows(或者也许是grep for Windows)这样的工具,这应该相对容易。 Gnu项目免费为Windows提供sed和grep。

使用VBScript,JScript或PowerShell的正则表达式功能也应该相对容易。

但是我想我会尝试使用原生批次。 FINDSTR具有原始的正则表达式支持,但它无法提取匹配的文本,因此批处理解决方案相当复杂。

下面的解决方案可以在一行中找到多个标记。它还能够计算每个不同标记的出现次数。 SET搜索和替换是不区分大小写的,因此我被迫使整个解决方案不区分大小写。

该解决方案只能处理长度约为8191字节的行。

只要包含标记的行数相对较小,即使对于非常大的文件,性能也应该很好。

@echo off
setlocal disableDelayedExpansion
set "file=test.txt"
set LF=^


::The two blank lines above are critical to create linefeed - do not remove.

::Clear any existing \mark variables
for /f "delims==" %%A in ('2^>nul set \mark{') do set "%%A="

::Find all lines that contain at least one valid mark and call a routine
::to parse out all marks
for /f eol^=^%LF%%LF%delims^= %%A in (
  'findstr /ri \mark{[0-9][0-9]*} "%file%"'
) do (
  set "ln=%%A"
  call :parseMarks
)

::Create file containing found marks only
>marks.txt (
  for /f "delims==" %%A in ('set \mark{') do echo %%A
)

::Create file containing found marks with counts
>markCounts.txt set \mark{

::Print the results
echo Here is a list of found marks
echo -----------------------------
type marks.txt
echo(
echo Here is a list of found marks with the counts
echo ---------------------------------------------
type markCounts.txt

exit /b

:parseMarks
setlocal enableDelayedExpansion
set "ln2=!ln:*\mark{=!"
if !ln2! neq !ln! (
  for /f "tokens=1* delims=}" %%B in ("x!ln2!x") do (
    endlocal
    echo(%%B|findstr /xr x[0-9][0-9]* >nul && (
      for /f "delims=x" %%D in ("%%B") do set /a \mark{%%D}+=1
    )
    set "ln=%%C"
  )
  if defined ln goto :parseMarks
)
exit /b

这是我使用的test.txt文件。它有许多问题测试用例,使批处理解决方案变得困难。

The \mark{} quick brown fox jump \mark{1} over the lazy dog
The quick \mark{10} brown fox jump over the \mark{99a} lazy dog
The quick \mark{}99} brown fox jump over the lazy \mark{100} dog! \MARK{22}!
The quick brown fox jump over the lazy dog \mark{1000} \mark{99
;The \mark{1} quick brown fox jump over the lazy dog
The \mark{!!99} quick brown fox jump over the lazy dog \mark{100}
\mark{22}The quick brown fox \mark{30} jump over the lazy dog
exclude \mark{100a}
exclude \mark{}
include \MARK{22}

这是我的结果

Here is a list of found marks
-----------------------------
\mark{1000}
\mark{100}
\mark{10}
\mark{1}
\mark{22}
\mark{30}

Here is a list of found marks with the counts
---------------------------------------------
\mark{1000}=1
\mark{100}=2
\mark{10}=1
\mark{1}=2
\mark{22}=3
\mark{30}=1

答案 1 :(得分:0)

如果您不想使用非Microsoft实用程序,可以使用此方法:

注意:此方法使用dostips.com中的strlen.bat例程HERE

@echo off
setlocal enabledelayedexpansion
for /f "tokens=*" %%x in (findOnce.txt) do call :work "%%x"
echo #%linenum% lines.
endlocal
goto :eof

:work
set line=%~1
if not "!line:\mark{=!"=="!line!" (
  call strlen line len
  for /l %%y in (0,1,!len!) do (
    if "!line:~%%y,1!"=="\" (
      set clip= \
    ) else (
      if "!clip!" neq "" ( 
        set clip=!clip!!line:~%%y,1!
        if "!line:~%%y,1!"=="}" (
          call :getcheck "!markset!" "!clip!"
          if "!markset!"=="" (
            set /a linenum=!linenum! + 1
            set markset=!markset!!clip!
            echo !linenum! !clip!
            set clip=
          ) else if "!check!"=="!markset!" (
            set /a linenum=!linenum! + 1
            set markset=!markset!!clip!
            echo !linenum! !clip!
            set clip=
          )
        )
      )
    )
  )
)
goto :eof

:getcheck
  set markset=%~1
  set clip=%~2
  call set check=%%markset:!clip!=%%
  if  "!check:~-1!"=="=" set check=!check:~,-1!
  if "!check:~1,1!"==" " set check=!check,~1!
goto :eof