为什么 findstr 不能正确处理大小写(在某些情况下)?
在 cmd.exe 中编写最近的一些脚本时,我需要将 findstr
与正则表达式一起使用 - 客户需要标准 cmd.exe 命令(没有 GnuWin32、Cygwin、VBS 或 Powershell)。
我只是想知道变量是否包含任何大写字符并尝试使用:
> set myvar=abc
> echo %myvar%|findstr /r "[A-Z]"
abc
> echo %errorlevel%
0
当 %myvar%
设置为 abc
时,实际上输出字符串并设置 < code>errorlevel 为 0,表示找到匹配项。
但是,完整列表变体:
> echo %myvar%|findstr /r "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]"
> echo %errorlevel%
1
不输出该行,并且它正确地将errorlevel
设置为1。
此外:
> echo %myvar%|findstr /r "^[A-Z]*$"
> echo %errorlevel%
1
也按预期工作。
我显然在这里遗漏了一些东西,即使只是 findstr
不知何故损坏了。
为什么第一个(范围)正则表达式在这种情况下不起作用?
还有更奇怪的地方:
> echo %myvar%|findstr /r "[A-Z]"
abc
> echo %myvar%|findstr /r "[A-Z][A-Z]"
abc
> echo %myvar%|findstr /r "[A-Z][A-Z][A-Z]"
> echo %myvar%|findstr /r "[A]"
上面的最后两个也没有输出字符串!
While writing some recent scripts in cmd.exe, I had a need to use findstr
with regular expressions - customer required standard cmd.exe commands (no GnuWin32 nor Cygwin nor VBS nor Powershell).
I just wanted to know if a variable contained any upper-case characters and attempted to use:
> set myvar=abc
> echo %myvar%|findstr /r "[A-Z]"
abc
> echo %errorlevel%
0
When %myvar%
is set to abc
, that actually outputs the string and sets errorlevel
to 0, saying that a match was found.
However, the full-list variant:
> echo %myvar%|findstr /r "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]"
> echo %errorlevel%
1
does not output the line and it correctly sets errorlevel
to 1.
In addition:
> echo %myvar%|findstr /r "^[A-Z]*$"
> echo %errorlevel%
1
also works as expected.
I'm obviously missing something here even if it's only the fact that findstr
is somehow broken.
Why does the first (range) regex not work in this case?
And yet more weirdness:
> echo %myvar%|findstr /r "[A-Z]"
abc
> echo %myvar%|findstr /r "[A-Z][A-Z]"
abc
> echo %myvar%|findstr /r "[A-Z][A-Z][A-Z]"
> echo %myvar%|findstr /r "[A]"
The last two above also does not output the string!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我相信这主要是一个可怕的设计缺陷。
我们都希望范围能够根据 ASCII 代码值进行整理。但它们没有 - 相反,范围基于几乎与 SORT 使用的默认序列匹配的排序规则序列。 编辑 -FINDSTR 使用的确切排序顺序现在可在 获取https://stackoverflow.com/a/20159191/1012053 标题为正则表达式字符类范围 [xy] 的部分。
我准备了一个文本文件,其中包含 1 - 255 范围内每个扩展 ASCII 字符的一行,不包括 10 (LF)、13 (CR) 和 26(Windows 上的 EOF)。
在每一行上,我都有一个字符,后跟一个空格,然后是该字符的十进制代码。然后,我通过 SORT 运行该文件,并将输出捕获到sortedChars.txt 文件中。
现在,我可以轻松地针对此排序文件测试任何正则表达式范围,并演示如何通过与 SORT 几乎相同的排序序列确定范围。
结果并不完全符合我们的预期,因为混合了字符 171、172 和 253。但结果是完全有道理的。行号前缀对应于SORT排序顺序,可以看到范围按照SORT顺序完全匹配。
这是另一个完全遵循 SORT 序列的范围测试:
存在一个带有字母字符的小异常。字符“a”在“A”和“Z”之间排序,但与 [AZ] 不匹配。 “z”排在“Z”之后,但它匹配 [AZ]。 [az] 也有相应的问题。 “A”排序在“a”之前,但它匹配 [az]。 “Z”在“a”和“z”之间排序,但它不匹配 [az]。
以下是 [AZ] 结果:
[az] 结果
Sort 将大写字母排在小写字母前面。 (编辑 - 我刚刚阅读了 SORT 的帮助,并了解到它不区分大小写。事实上,我的 SORT 输出始终将大写放在小写之前,这可能是输入顺序的结果。)< /em> 但正则表达式显然将小写字母排在大写字母之前。以下所有范围均无法匹配任何字符。
颠倒顺序即可找到字符。
正则表达式对其他字符的排序与 SORT 不同,但我还没有准确的列表。
I believe this is mostly a horrible design flaw.
We all expect the ranges to collate based on the ASCII code value. But they don't - instead the ranges are based on a collation sequence that nearly matches the default sequence used by SORT. EDIT -The exact collation sequence used by FINDSTR is now available at https://stackoverflow.com/a/20159191/1012053 under the section titled Regex character class ranges [x-y].
I prepared a text file containing one line for each extended ASCII character from 1 - 255, excluding 10 (LF), 13 (CR), and 26 (EOF on Windows).
On each line I have the character, followed by a space, followed by the decimal code for the character. I then ran the file through SORT and captured the output in a sortedChars.txt file.
I now can easily test any regex range against this sorted file and demonstrate how the range is determined by a collation sequence that is nearly the same as SORT.
The results are not quite what we expected in that chars 171, 172 and 253 are thrown in the mix. But the results make perfect sense. The line number prefix corresponds to the SORT collation sequence, and you can see that the range exactly matches according to the SORT sequence.
Here is another range test that exactly follows the SORT sequence:
There is one small anomaly with alpha characters. Character "a" sorts between "A" and "Z" yet it does not match [A-Z]. "z" sorts after "Z", yet it matches [A-Z]. There is a corresponding problem with [a-z]. "A" sorts before "a", yet it matches [a-z]. "Z" sorts between "a" and "z", yet it does not match [a-z].
Here are the [A-Z] results:
And the [a-z] results
Sort sorts upper case before lower case. (EDIT - I just read the help for SORT and learned that it does not differentiate between upper and lower case. The fact that my SORT output consistently put upper before lower is probably a result of the order of the input.) But regex apparently sorts lower case before upper case. All of the following ranges fail to match any characters.
Reversing the order finds the characters.
There are additional characters that regex sorts differently than SORT, but I haven't got a precise list.
因此,如果您想要
仅数字:
FindStr /R“^[0123-9]*$”
八进制:
FindStr /R "^[0123-7]*$"
八
十六进制:
FindStr /R "^[0123-9aAb-Cd-EfF]*$"
十六
不带重音符号的 alpha :
FindStr /R "^[aAb-Cd-EfFg-Ij-NoOp-St-Uv-YzZ] *$"
字母数字 :
FindStr /R "^[0123-9aAb-Cd-EfFg-Ij-NoOp-St-Uv-YzZ]*$"
字母数字
So if you want
only numbers :
FindStr /R "^[0123-9]*$"
octal :
FindStr /R "^[0123-7]*$"
hexadécimal :
FindStr /R "^[0123-9aAb-Cd-EfF]*$"
alpha with no accent :
FindStr /R "^[aAb-Cd-EfFg-Ij-NoOp-St-Uv-YzZ]*$"
alphanumeric :
FindStr /R "^[0123-9aAb-Cd-EfFg-Ij-NoOp-St-Uv-YzZ]*$"
这似乎是由于在正则表达式搜索中使用范围引起的。
该范围内的第一个字符不会出现这种情况。对于非范围根本不会发生。
根据
SS64 CMD FINDSTR
页面(令人惊叹的圆度的显示,参考这个问题),范围[AZ]
:为了解决我的环境中的问题,我只是使用了特定的正则表达式(例如
[ABCD]
而不是[AD]
)。对于那些被允许的人来说,更明智的方法是下载 CygWin 或 GnuWin32 并使用其中一个包中的grep
。This appears to be caused by the use of ranges within regular expression searches.
It doesn't occur for the first character in the range. It doesn't occur at all for non-ranges.
According to the
SS64 CMD FINDSTR
page (which, in a stunning display of circularity, references this question), the range[A-Z]
:To get around the problem in my environment, I simply used specific regular expressions (such as
[ABCD]
rather than[A-D]
). A more sensible approach for those that are allowed would be to download CygWin or GnuWin32 and usegrep
from one of those packages.楼上各位都错了。
alpha 字符顺序如下:
aAbBcCdDeE..zZ
所以回显 | findstr /r "[AZ]" 不返回任何内容,因为
a
超出了该范围。echo abc|findstr /r "[AZ][AZ][AZ]"
也不返回任何内容,因为第一个范围组匹配b
,第二个范围组匹配c< /code> 第三个没有匹配任何内容,因此整个正则表达式模式什么也没找到。
如果您想匹配拉丁字母的任何字符 - 请使用
[aZ]
。Everyone above is wrong.
The alpha chars order is the follwoing:
aAbBcCdDeE..zZ
so
echo a | findstr /r "[A-Z]"
returns nothing, sincea
is outside of that range.echo abc|findstr /r "[A-Z][A-Z][A-Z]"
also returns nothing, since first range group matchesb
, second one matchesc
and the third one matches nothing and thus the whole regex pattern finds nothing.If you like to match any character of latin alphabet - use
[a-Z]
.