我必须检查存储在变量中的字符串的有效性,我不能使用外部 CLI 实用程序(grep、awk 等),所以我选择了 FINDSTR。该字符串具有以下格式(在正则表达式中):
([1-9][0-9]*:".*"(|".*")*)
我不知道如何检查子模式(|。“*”)。目前我的代码是:
((ECHO.) | (SET /P "=(11:"a"|"b"|"c")") | (FINDSTR /R /C:"^([1-9][0-9]*:".*")$"))
问候。
我必须检查存储在变量中的字符串的有效性,我不能使用外部 CLI 实用程序(grep、awk 等),所以我选择了 FINDSTR。该字符串具有以下格式(在正则表达式中):
([1-9][0-9]*:".*"(|".*")*)
我不知道如何检查子模式(|。“*”)。目前我的代码是:
((ECHO.) | (SET /P "=(11:"a"|"b"|"c")") | (FINDSTR /R /C:"^([1-9][0-9]*:".*")$"))
问候。
Mat M 关于 FINDSTR 的限制是正确的。FINDSTR 正则表达式支持非常原始且非标准。在命令行中键入HELP FINDSTR
或FINDSTR /?
以获得支持的简要概要。有关详细说明,请参阅Windows FINDSTR 命令有哪些未记录的功能和限制?
我喜欢 Harry Johnston 的评论 - 使用 VBScript 或 JavaScript 创建解决方案非常容易。我认为这将是一个更好的选择。
但是,这是一个本地批处理解决方案。我已经合并了关于 OP 在对 Mat M 的回答的评论中声明的子模式数量的额外规则。
解决方案非常棘手。由于管道的工作方式,在将 ECHO 输出传送到 FINDSTR 时,特殊字符可能会导致问题。管道的每一侧都在其自己的 CMD 会话中执行。特殊字符必须被引用、转义两次或仅通过延迟扩展公开。我选择使用延迟扩展,但!
字符必须转义两次以确保延迟扩展发生在正确的时间。
解析可变数量的子模式的最简单方法是用换行符替换分隔符并使用 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
据我所知,findstr无法对正则表达式进行分组,所以(|".*")*
是禁止的。如果你知道你有多少块并且你像这样复制你的代码
FINDSTR /R /C:"^([1-9][0-9]*:\"..*\"|\"..*\"|\"..*\")$"
这样,如果您确定块的数量是恒定的,""
如果需要有空的,那么您可以检查它。
表达式中的双引号将被忽略,除非您在它们前面加上 \。
该 ..*
构造旨在替换.+
: 一个或多个字符。