16

在 cmd.exe 中编写一些最近的脚本时,我需要使用findstr正则表达式 - 客户需要标准 cmd.exe 命令(没有 GnuWin32、Cygwin、VBS 或 Powershell)。

我只是想知道变量是否包含任何大写字符并尝试使用:

> set myvar=abc
> echo %myvar%|findstr /r "[A-Z]"
abc
> echo %errorlevel%
0

%myvar%设置为abc时,实际上输出字符串并设置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]"

上面最后两个也不输出字符串!!

4

4 回答 4

15

我相信这主要是一个可怕的设计缺陷。

我们都希望根据 ASCII 码值来整理范围。但它们没有——取而代之的是,范围基于与 SORT 使用的默认序列几乎匹配的整理序列。编辑 - FINDSTR 使用的确切排序规则现在可在https://stackoverflow.com/a/20159191/1012053标题为Regex character class range [xy]的部分下找到。

我为从 1 到 255 的每个扩展 ASCII 字符准备了一个文本文件,其中不包括 10 (LF)、13 (CR) 和 26 (Windows 上的 EOF)。在每一行我都有字符,后跟一个空格,然后是字符的十进制代码。然后我通过 SORT 运行该文件并将输出捕获到 sortedChars.txt 文件中。

我现在可以轻松地针对这个排序文件测试任何正则表达式范围,并演示该范围是如何由与 SORT 几乎相同的排序规则确定的。

>findstr /nrc:"^[0-9]" sortedChars.txt
137:0 048
138:½ 171
139:¼ 172
140:1 049
141:2 050
142:² 253
143:3 051
144:4 052
145:5 053
146:6 054
147:7 055
148:8 056
149:9 057

结果并不完全符合我们的预期,因为字符 171、172 和 253 被混合在一起。但结果非常合理。行号前缀对应 SORT 排序顺序,可以看到范围完全按照 SORT 顺序匹配。

这是另一个完全遵循 SORT 序列的范围测试:

>findstr /nrc:"^[!-=]" sortedChars.txt
34:! 033
35:" 034
36:# 035
37:$ 036
38:% 037
39:& 038
40:( 040
41:) 041
42:* 042
43:, 044
44:. 046
45:/ 047
46:: 058
47:; 059
48:? 063
49:@ 064
50:[ 091
51:\ 092
52:] 093
53:^ 094
54:_ 095
55:` 096
56:{ 123
57:| 124
58:} 125
59:~ 126
60:¡ 173
61:¿ 168
62:¢ 155
63:£ 156
64:¥ 157
65:₧ 158
66:+ 043
67:∙ 249
68:< 060
69:= 061

有一个带有字母字符的小异常。字符“a”在“A”和“Z”之间排序,但它不匹配 [AZ]。“z”排在“Z”之后,但它与 [AZ] 匹配。[az] 有相应的问题。"A" 排在 "a" 之前,但它匹配 [az]。“Z”在“a”和“z”之间排序,但它不匹配 [az]。

以下是 [AZ] 结果:

>findstr /nrc:"^[A-Z]" sortedChars.txt
151:A 065
153:â 131
154:ä 132
155:à 133
156:å 134
157:Ä 142
158:Å 143
159:á 160
160:ª 166
161:æ 145
162:Æ 146
163:B 066
164:b 098
165:C 067
166:c 099
167:Ç 128
168:ç 135
169:D 068
170:d 100
171:E 069
172:e 101
173:é 130
174:ê 136
175:ë 137
176:è 138
177:É 144
178:F 070
179:f 102
180:ƒ 159
181:G 071
182:g 103
183:H 072
184:h 104
185:I 073
186:i 105
187:ï 139
188:î 140
189:ì 141
190:í 161
191:J 074
192:j 106
193:K 075
194:k 107
195:L 076
196:l 108
197:M 077
198:m 109
199:N 078
200:n 110
201:ñ 164
202:Ñ 165
203:ⁿ 252
204:O 079
205:o 111
206:ô 147
207:ö 148
208:ò 149
209:Ö 153
210:ó 162
211:º 167
212:P 080
213:p 112
214:Q 081
215:q 113
216:R 082
217:r 114
218:S 083
219:s 115
220:ß 225
221:T 084
222:t 116
223:U 085
224:u 117
225:û 150
226:ù 151
227:ú 163
228:ü 129
229:Ü 154
230:V 086
231:v 118
232:W 087
233:w 119
234:X 088
235:x 120
236:Y 089
237:y 121
238:ÿ 152
239:Z 090
240:z 122

[az] 结果

>findstr /nrc:"^[a-z]" sortedChars.txt
151:A 065
152:a 097
153:â 131
154:ä 132
155:à 133
156:å 134
157:Ä 142
158:Å 143
159:á 160
160:ª 166
161:æ 145
162:Æ 146
163:B 066
164:b 098
165:C 067
166:c 099
167:Ç 128
168:ç 135
169:D 068
170:d 100
171:E 069
172:e 101
173:é 130
174:ê 136
175:ë 137
176:è 138
177:É 144
178:F 070
179:f 102
180:ƒ 159
181:G 071
182:g 103
183:H 072
184:h 104
185:I 073
186:i 105
187:ï 139
188:î 140
189:ì 141
190:í 161
191:J 074
192:j 106
193:K 075
194:k 107
195:L 076
196:l 108
197:M 077
198:m 109
199:N 078
200:n 110
201:ñ 164
202:Ñ 165
203:ⁿ 252
204:O 079
205:o 111
206:ô 147
207:ö 148
208:ò 149
209:Ö 153
210:ó 162
211:º 167
212:P 080
213:p 112
214:Q 081
215:q 113
216:R 082
217:r 114
218:S 083
219:s 115
220:ß 225
221:T 084
222:t 116
223:U 085
224:u 117
225:û 150
226:ù 151
227:ú 163
228:ü 129
229:Ü 154
230:V 086
231:v 118
232:W 087
233:w 119
234:X 088
235:x 120
236:Y 089
237:y 121
238:ÿ 152
240:z 122

排序将大写字母排在小写字母之前。(编辑 - 我刚刚阅读了 SORT 的帮助并了解到它不区分大小写。我的 SORT 输出始终将大写放在小写之前的事实可能是输入顺序的结果。) 但正则表达式显然排序小写在大写之前。以下所有范围均无法匹配任何字符。

>findstr /nrc:"^[A-a]" sortedChars.txt

>findstr /nrc:"^[B-b]" sortedChars.txt

>findstr /nrc:"^[C-c]" sortedChars.txt

>findstr /nrc:"^[D-d]" sortedChars.txt

颠倒顺序找到字符。

>findstr /nrc:"^[a-A]" sortedChars.txt
151:A 065
152:a 097

>findstr /nrc:"^[b-B]" sortedChars.txt
163:B 066
164:b 098

>findstr /nrc:"^[c-C]" sortedChars.txt
165:C 067
166:c 099

>findstr /nrc:"^[d-D]" sortedChars.txt
169:D 068
170:d 100

还有其他字符的正则表达式排序不同于 SORT,但我没有一个精确的列表。

于 2012-01-07T06:15:55.910 回答
6

所以如果你想

  • 只有数字: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]*$"

于 2015-12-10T16:52:20.220 回答
3

这似乎是由于在正则表达式搜索中使用范围造成的。

范围内的第一个字符不会出现这种情况。对于非范围,它根本不会发生。

> echo a | findstr /r "[A-C]"
> echo b | findstr /r "[A-C]"
    b
> echo c | findstr /r "[A-C]"
    c
> echo d | findstr /r "[A-C]"
> echo b | findstr /r "[B-C]"
> echo c | findstr /r "[B-C]"
    c

> echo a | findstr /r "[ABC]"
> echo b | findstr /r "[ABC]"
> echo c | findstr /r "[ABC]"
> echo d | findstr /r "[ABC]"
> echo b | findstr /r "[BC]"
> echo c | findstr /r "[BC]"

> echo A | findstr /r "[A-C]"
    A
> echo B | findstr /r "[A-C]"
    B
> echo C | findstr /r "[A-C]"
    C
> echo D | findstr /r "[A-C]"

根据SS64 CMD FINDSTR页面(以惊人的循环性显示,引用了这个问题),范围[A-Z]

... 包括完整的英文字母表,包括大写和小写(“a”除外),以及带有变音符号的非英文字母字符。

为了在我的环境中解决这个问题,我只是使用了特定的正则表达式(例如[ABCD]而不是[A-D])。对于那些被允许的人来说,一种更明智的方法是下载CygWinGnuWin32grep从其中一个包中使用。

于 2010-06-11T06:42:52.307 回答
-1

楼上的人都错了。alpha 字符顺序如下:aAbBcCdDeE..zZ 所以echo a | findstr /r "[A-Z]"不返回任何内容,因为a超出了该范围。

echo abc|findstr /r "[A-Z][A-Z][A-Z]"也不返回任何内容,因为第一个范围组匹配b,第二个匹配c,第三个不匹配,因此整个正则表达式模式什么也找不到。

如果您想匹配拉丁字母的任何字符,请使用[a-Z].

于 2015-07-15T11:20:20.807 回答