¿Por qué findstr no maneja el estuche correctamente (en algunas circunstancias)?

Mientras escribía algunas secuencias de comandos recientes en cmd.exe, tuve la necesidad de usar findstr con expresiones regulares: los comandos de cmd.exe estándar requeridos por el cliente (no GnuWin32 ni Cygwin ni VBS ni Powershell).

Solo quería saber si una variable contenía caracteres en mayúscula e intentaba usar:

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

Cuando %myvar% se establece en abc , eso realmente genera la cadena y establece errorlevel en 0, indicando que se encontró una coincidencia.

Sin embargo, la variante de lista completa:

 > echo %myvar%|findstr /r "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]" > echo %errorlevel% 1 

no da salida a la línea y establece correctamente errorlevel en 1.

En adición:

 > echo %myvar%|findstr /r "^[AZ]*$" > echo %errorlevel% 1 

también funciona como se esperaba

Obviamente me falta algo aquí, incluso si es solo el hecho de que findstr está roto de alguna manera.

¿Por qué la primera expresión regular (rango) no funciona en este caso?


Y aún más rarezas:

 > echo %myvar%|findstr /r "[AZ]" abc > echo %myvar%|findstr /r "[AZ][AZ]" abc > echo %myvar%|findstr /r "[AZ][AZ][AZ]" > echo %myvar%|findstr /r "[A]" 

¡Los últimos dos anteriores tampoco producen la cadena!

Creo que esto es principalmente un error de diseño horrible.

Todos esperamos que los rangos se clasifiquen según el valor del código ASCII. Pero no lo hacen; en cambio, los rangos se basan en una secuencia de intercalación que casi coincide con la secuencia predeterminada utilizada por SORT. EDITAR: la secuencia de intercalación exacta utilizada por FINDSTR ahora está disponible en https://stackoverflow.com/a/20159191/1012053 en la sección titulada Rangos de clases de caracteres Regex [xy] .

Preparé un archivo de texto que contiene una línea para cada carácter ASCII extendido del 1 al 255, excluyendo 10 (LF), 13 (CR) y 26 (EOF en Windows). En cada línea, tengo el carácter, seguido de un espacio, seguido del código decimal para el personaje. Luego ejecuté el archivo a través de SORT y capturé el resultado en un archivo sortedChars.txt.

Ahora puedo probar fácilmente cualquier rango de expresiones regulares contra este archivo ordenado y demostrar cómo el rango está determinado por una secuencia de intercalación que es casi igual a 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 

Los resultados no son exactamente los esperados porque los caracteres 171, 172 y 253 se incluyen en la mezcla. Pero los resultados tienen perfecto sentido. El prefijo del número de línea corresponde a la secuencia de clasificación SORT, y puede ver que el rango coincide exactamente de acuerdo con la secuencia SORT.

Aquí hay otra prueba de rango que sigue exactamente la secuencia 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 

Hay una pequeña anomalía con caracteres alfabéticos. El carácter "a" ordena entre "A" y "Z" pero no coincide con [AZ]. "z" ordena después de "Z", pero coincide con [AZ]. Hay un problema correspondiente con [az]. "A" ordena antes de "a", pero coincide con [az]. "Z" ordena entre "a" y "z", pero no coincide con [az].

Aquí están los resultados [AZ]:

 >findstr /nrc:"^[AZ]" 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 

Y los resultados [az]

 >findstr /nrc:"^[az]" 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 

Ordenar ordena mayúsculas antes minúsculas. (EDITAR - Acabo de leer la ayuda para SORT y aprendí que no distingue entre mayúsculas y minúsculas. El hecho de que mi salida SORT constantemente suba antes que abajo es probablemente el resultado del orden de la entrada.) Pero parece que la expresión regular minúsculas antes de mayúsculas. Todos los siguientes rangos no coinciden con ningún carácter.

 >findstr /nrc:"^[Aa]" sortedChars.txt >findstr /nrc:"^[Bb]" sortedChars.txt >findstr /nrc:"^[Cc]" sortedChars.txt >findstr /nrc:"^[Dd]" sortedChars.txt 

Invertir el orden encuentra los caracteres.

 >findstr /nrc:"^[aA]" sortedChars.txt 151:A 065 152:a 097 >findstr /nrc:"^[bB]" sortedChars.txt 163:B 066 164:b 098 >findstr /nrc:"^[cC]" sortedChars.txt 165:C 067 166:c 099 >findstr /nrc:"^[dD]" sortedChars.txt 169:D 068 170:d 100 

Hay caracteres adicionales que Regex ordena de forma diferente que SORT, pero no tengo una lista precisa.

Entonces si quieres

  • solo números: FindStr /R "^[0123-9]*$"

  • octal: FindStr /R "^[0123-7]*$"

  • hexadécimal: FindStr /R "^[0123-9aAb-Cd-EfF]*$"

  • alfa sin acento: FindStr /R "^[aAb-Cd-EfFg-Ij-NoOp-St-Uv-YzZ]*$"

  • alfanumérico: FindStr /R "^[0123-9aAb-Cd-EfFg-Ij-NoOp-St-Uv-YzZ]*$"

Esto parece ser causado por el uso de rangos dentro de las búsquedas de expresiones regulares.

No ocurre para el primer personaje en el rango. No ocurre en absoluto para los no rangos.

 > echo a | findstr /r "[AC]" > echo b | findstr /r "[AC]" b > echo c | findstr /r "[AC]" c > echo d | findstr /r "[AC]" > echo b | findstr /r "[BC]" > echo c | findstr /r "[BC]" 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 "[AC]" A > echo B | findstr /r "[AC]" B > echo C | findstr /r "[AC]" C > echo D | findstr /r "[AC]" 

De acuerdo con la página SS64 CMD FINDSTR (que, en una deslumbrante muestra de circularidad, hace referencia a esta pregunta), el rango [AZ] :

… incluye el alfabeto inglés completo, tanto en mayúscula como en minúscula (a excepción de “a”), así como caracteres alfa no ingleses con signos diacríticos.

Para evitar el problema en mi entorno, simplemente usé expresiones regulares específicas (como [ABCD] lugar de [AD] ). Un enfoque más sensato para aquellos que están permitidos sería descargar CygWin o GnuWin32 y usar grep de uno de esos paquetes.

Todos los de arriba están equivocados. El orden alfa de caracteres es el siguiente: aAbBcCdDeE..zZ así echo a | findstr /r "[AZ]" echo a | findstr /r "[AZ]" no devuelve nada, ya que a está fuera de ese rango.

echo abc|findstr /r "[AZ][AZ][AZ]" tampoco devuelve nada, ya que el primer grupo de rangos coincide con b , el segundo coincide con c y el tercero no concuerda con nada, por lo que el patrón de expresiones regulares no encuentra nada.

Si desea hacer coincidir cualquier carácter del alfabeto latino, use [aZ] .