0

.txtファイルで特定のテキストまたは単語を見つけることができるバッチファイルにコードがあるかどうか疑問に思っています。

例えば:

  1. 怠惰な犬の上にすばやく茶色のキツネが\mark{1}ジャンプします
  2. 速い\mark{10}茶色のキツネが怠惰な犬を飛び越えます
  3. 速い茶色のキツネは怠惰な\mark{100}犬を飛び越えます
  4. 速い茶色のキツネが怠惰な犬を飛び越えます\mark{1000}
  5. \mark{1}クイックブラウンフォックスは怠惰な犬を飛び越えます
  6. 速い茶色のキツネが怠惰な犬を飛び越えます\mark{100}
  7. 速い茶色のキツネ\mark{30}は怠惰な犬を飛び越えます

上記の例からわかるように、「\ mark {Number here}」という単語を検索します。また、同じ単語が出現する可能性がある場合、たとえば1行目と5行目も検索します。 、最初の行の「\ mark {1}」のみが表示され、5行目の同じ単語は無視されます

したがって、結果はtxtファイルに出力されます。

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

2 に答える 2

2

これは、Windows 用の sed (または Windows 用の grep) などのツールをダウンロードすれば比較的簡単です。Gnu プロジェクトには、Windows 用の sed と grep の両方が無料で用意されています。

また、VBScript、JScript、または powershell の正規表現機能を使用すると、比較的簡単に実行できます。

しかし、ネイティブ バッチを使用して試してみようと思いました。FINDSTR は基本的な正規表現をサポートしていますが、一致するテキストを抽出できないため、バッチ ソリューションはかなり複雑です。

以下のソリューションでは、1 行で複数のマークを見つけることができます。また、個別のマークごとに出現回数をカウントすることもできます。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
于 2012-08-28T11:37:00.487 に答える
0

Microsoft 以外のユーティリティを使用せずに実行する場合は、次の方法を使用できます。

注:この方法では、こちらから入手できる dotips.com の strlen.bat ルーチンを使用します。

@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
于 2012-08-28T21:04:08.040 に答える