我想验证用户的输入并将输入限制为仅字母数字字符(也可能允许使用下划线),但我不确定哪种方法最适合此操作。
我在 SA 上看到了各种示例,第一个对我提出一些问题的示例如下:
:input
set "in="
set /p "in=Please enter your username: "
ECHO(%in%|FINDSTR /ri "^[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ][0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ]*$" >nul || (
goto input
)
我看到第二个案例与第一个相同(正如预期的那样,开头^
和结尾*$
)。
^
*$
当以下内容也适用时,为什么需要额外的案例和需要?:
:input
set "in="
set /p "in=Please enter your username: "
ECHO(%in%|FINDSTR /ri "[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ]" >nul || (
goto input
)
最后,FOR /F
我在这里也注意到了循环方法:
for /f "delims=1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" %%a in ("%in%") do goto :input
与前面提到的 FINDSTR 正则表达式相比,使用它是否有任何(不利)优势?
为了安全地验证用户输入,这两种方法都是可靠的,但您必须改进它们:
findstr
方法首先,让我们关注这样的搜索字符串^[...][...]*$
(其中...
代表一个字符类,意思是一组字符):一个字符类[...]
匹配集合中的任何一个字符...
;*
表示重复,因此匹配零次或多次出现,因此[...]*
匹配 set 中出现的零次或多次字符...
;因此,[...][...]*
匹配 set 中出现的一个或多个字符...
。前导^
将匹配锚定到行的开头,尾随$
将其锚定到行尾;因此,当指定了两个锚点时,整行必须与搜索字符串匹配。
关于字符类[...]
:根据线程Windows FINDSTR 命令的未记录功能和限制是什么?,课程有问题;例如,该类[A-Z]
将小写字母匹配b
到z
,并将[a-z]
大写字母匹配A
到Y
(这当然无关紧要,如果进行了不区分大小写的搜索,因此何时/I
给出);类[0-9]
可能匹配²
或³
,具体取决于当前代码页;[A-Z]
并且[a-z]
可能匹配特殊字母,例如Á
或á
,也取决于当前代码页。因此,为了仅安全地匹配某些字符,不要使用范围,而是单独指定每个字符,例如[0123456789]
,[ABCDEFGHIJKLMNOPQRSTUVWXYZ]
或[abcdefghijklmnopqrstuvwxyz]
。
所有这些都引导我们进入以下findstr
命令行:
findstr /R /I "^[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ][0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ]*$"
尽管如此,使用管道的整个方法echo
可能仍然会失败,因为像"
, &
, ^
, %
, !
, (
, )
, <
, >
,等特殊字符|
可能会导致语法错误或其他意外行为。为避免这种情况,我们需要建立延迟扩展,以便特殊字符对命令解析器隐藏。但是,由于管道 ( |
)cmd
为任一侧(继承当前环境)初始化了新实例,我们需要确保在左子cmd
实例中而不是在父实例中进行实际的变量扩展,如下所示:
:INPUT
set "IN="
set /P IN="Please enter your username: "
cmd /V /C echo(^^!IN^^!| findstr /R /I "^[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ][0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ]*$" > nul || goto :INPUT
cmd
需要额外的显式实例来启用延迟扩展 ( /V
),因为管道启动的实例已禁用延迟扩展。
感叹号的双重转义^^!
仅在父cmd
实例中也启用了延迟扩展的情况下才需要;如果没有,单次转义^!
就足够了,但双次转义也无妨。
for /F
方法这种方法使生活更轻松,因为不涉及管道,因此您不必处理多个cmd
实例,但仍有改进的空间。同样,特殊字符可能会引起麻烦,因此需要启用延迟扩展。
该for /F
循环忽略空行和这样的开始与默认eol
字符,分号;
。要禁用该eol
选项,只需定义一个分隔符,因此eol
隐藏在delims
. 空行不会被迭代,因此在goto
用户输入为空的情况下,您的方法中的命令永远不会执行。因此,我们必须使用if
语句显式捕获空的用户输入。现在所有这些都导致了以下代码:
setlocal EnableDelayedExpansion
:INPUT
set "IN="
set /P IN="Please enter your username: "
if not defined IN goto :INPUT
for /F "delims=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ eol=0" %%Z in ("!IN!") do goto :INPUT
endlocal
这种方法只检测大写字母;要包括小写字母,您必须将它们添加到delims
选项中:delims=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
.
请注意,变量IN
不再可用endlocal
,但无论如何这应该是脚本的最后一个命令。
为了检测for /F
循环是否迭代,有一个未公开的特性,我们可以利用它:for /F
如果没有迭代,则返回非零退出代码,因此可以使用条件执行运算符&&
或||
;所以,当用户输入为空时,循环不迭代,然后||
;为此,for /F
循环必须括在括号内:
setlocal EnableDelayedExpansion
:INPUT
set "IN="
set /P IN="Please enter your username: "
if not defined IN goto :INPUT
(for /F "delims=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ eol=0" %%Z in ("!IN!") do rem/) && goto :INPUT
endlocal
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句