5

変数に格納されている文字列の有効性を確認する必要があります。外部CLIユーティリティ(grep、awkなど)を使用できないため、FINDSTRを選択しました。文字列の形式は(正規表現で)次のとおりです。

([1-9][0-9]*:".*"(|".*")*)

サブパターン(|。 "*")を確認する方法がわかりません。現在、私のコードは次のとおりです。

((ECHO.) | (SET /P "=(11:"a"|"b"|"c")") | (FINDSTR /R /C:"^([1-9][0-9]*:".*")$"))

よろしく。

4

2 に答える 2

6

Mat M は、FINDSTR の制限について正しいです。FINDSTR 正規表現のサポートは、非常に原始的で非標準です。コマンド ラインからHELP FINDSTRorを入力すると、サポートされている内容の簡単な概要が表示されます。FINDSTR /?詳細な説明については、Windows FINDSTR コマンドの文書化されていない機能と制限事項は何ですか? を参照してください。

Harry Johnston のコメントが気に入りました - VBScript または JavaScript を使用してソリューションを作成するのは非常に簡単です。それははるかに良い選択だと思います。

しかし、これはネイティブのバッチ ソリューションです。OPがMat Mの回答へのコメントで述べたサブパターンの数に関する追加のルールを組み込みました。

解決策は驚くほどトリッキーです。特殊文字は、ECHO 出力を FINDSTR にパイプするときに問題を引き起こす可能性があります。これは、パイプの動作が原因です。パイプの各側は、独自の CMD セッションで実行されます。特殊文字は、引用するか、2 回エスケープするか、遅延展開によってのみ公開する必要があります。遅延展開を使用!することにしましたが、遅延展開が正しいタイミングで行われるようにするには、文字を 2 回エスケープする必要があります。

可変数のサブパターンを解析する最も簡単な方法は、区切り文字を改行に置き換え、FOR /F を使用して各サブパターンを反復することです。

私のコードの上半分は、一連の文字列を簡単に反復およびテストするための脆弱なコーディング ハーネスです。<space> ; , = <tab> *のいずれかまたは文字列内では正しく機能しません?。また、各文字列で引用符のバランスを取る必要があります。

しかし、より重要な検証ルーチンは、var 変数内の任意の文字列を処理できます。

@echo off
setlocal
set LF=^


::Above 2 blank lines are critical for creating a linefeed variable. Do not remove

set test=a

for %%S in (
  "(3:"a"|"c"|"c")"
  "(11:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")"
  "(4:"a"|"b"|"c")"
  "(10:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")"
  "(3:"a"|"b"|"c""
  "(3:"a"|"b^|c")"
  "(3:"a"|"b"|c)"
  "(3:"a"|"b"||"c")"
  "(3:"a"|"b"|;|"c")"
) do (
  set "var=%%~S"
  call :validate
)
exit /b

:validate
setlocal enableDelayedExpansion
cmd /v:on /c echo ^^^!var^^^!|findstr /r /c:"^([1-9][0-9]*:.*)$" >nul || (call :invalid  FINDSTR fail& exit /b)
if "!var:||=!" neq "!var!" (call :invalid double pipe fail& exit /b)
for /f "delims=(:" %%N in ("!var!") do set "expectedCount=%%N"
set "str=!var:*:=!"
set "str=!str:~0,-1!"
set foundCount=0
for %%A in ("!LF!") do for /f eol^=^%LF%%LF%^ delims^=  %%B in ("!str:|=%%~A!") do (
  if %%B neq "%%~B" (call :invalid sub-pattern fail& exit /b)
  set /a foundCount+=1
)
if %foundCount% neq %expectedCount% (call :invalid count fail& exit /b)
echo Valid: !var!
exit /b
:invalid
echo Invalid - %*: !var!
exit /b

バッチスクリプトを実行した後の結果は次のとおりです

Valid: (3:"a"|"c"|"c")
Valid: (11:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")
Invalid - count fail: (4:"a"|"b"|"c")
Invalid - count fail: (10:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")
Invalid - FINDSTR fail: (3:"a"|"b"|"c"
Invalid - sub-pattern fail: (3:"a"|"b|c")
Invalid - sub-pattern fail: (3:"a"|"b"|c)
Invalid - double pipe fail: (3:"a"|"b"||"c")
Invalid - sub-pattern fail: (3:"a"|"b"|;|"c")


アップデート

遅延拡張の有効化をパイプの後まで延期することにより、:validateルーチンを少し単純化できます。これは、パイプの左側で をCMD /V:ON二重にエスケープすることを心配する必要がなくなったことを意味します。!

:validate
cmd /v:on /c echo !var!|findstr /r /c:"^([1-9][0-9]*:.*)$" >nul || (call :invalid  FINDSTR fail& exit /b)
setlocal enableDelayedExpansion
... remainder unchanged
于 2012-09-24T18:16:22.470 に答える
2

私の知る限り、findstrは正規表現をグループ化できないため、ノーノー(|".*")*です。ブロックの数がわかっている場合、次のようにコードを複製します。

FINDSTR /R /C:"^([1-9][0-9]*:\"..*\"|\"..*\"|\"..*\")$"

このようにして、ブロックの数が一定であり、必要に応じて空のブロックがあることが確実な""場合は、それを確認できます。

\ を前に付けない限り、式内の二重引用符は無視されます。
この 構造は、 1 つまたは複数の文字..*を置き換えることを意図しています。.+

于 2012-09-23T23:11:39.443 に答える