我必须检查存储在variables中的string的有效性,我不能使用外部CLI实用程序(grep,awk等),所以我select了FINDSTR。 该string具有这种格式(在正则expression式中):
([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创建解决方案将非常简单。 我认为这将是一个更好的选择。
但是,这是一个本地批处理解决方案。 我已经在Mat M的回答中加入了关于OP在评论中陈述的子模式的数量的额外规则。
解决方案是令人惊讶的棘手。 由于管道的工作方式,在将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")
更新
通过推迟延迟扩展的启用,直到CMD /V:ON
管道之后,可以简化一些:validate
程序。 这意味着我不必再担心双重逃跑了!
在管道的左侧。
: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不能将regexps分组,所以(|".*")*
是一个no-no。 如果你知道你有多少块,并且你像这样复制你的代码
FINDSTR /R /C:"^([1-9][0-9]*:\"..*\"|\"..*\"|\"..*\")$"
这样,如果你确定块的数量是恒定的,如果需要的话,有空的""
,那么你可以检查它。
表达式中的双引号将被忽略,除非用“\”前缀。
..*
构造是为了替换.+
:一个或多个字符。