¿Por qué el rango [01-12] no funciona como se esperaba?
91
Estoy tratando de usar el patrón de rango [01-12]en expresiones regulares para que coincida con dos dígitos mm, pero esto no funciona como se esperaba.
Estás haciendo coincidir caracteres , no secuencias de caracteres . Básicamente, estás haciendo coincidir 0, 1 a 1 y 2 (es decir, 0, 1 y 2). Considere esto: [a-z0-9]esto coincide con todas las letras minúsculas y todos los dígitos, pero solo como un solo carácter.
Lasse V. Karlsen
fwiw, creé una herramienta de JavaScript que crea una expresión regular altamente optimizada a partir de dos entradas (mínimo / máximo) github.com/jonschlinkert/to-regex-range
jonschlinkert
0 [1-9] | 1 [0-2] -> 0 | 1 | 2 -> [] s en una expresión regular denotan una clase de carácter. Si no se especifican rangos, implícitamente ordena cada carácter.
Badri Gs
¿Necesitas combinarlo con expresión regular pura? De lo contrario, puede: 1.) simplemente usar el \d+patrón, 2.) convertir las cadenas coincidentes en números en su código. y luego, 3.) verifique el rango de números como if(num >= 0 && num <= 12){ /*do something*/ }. Es mucho más rápido y flexible.
acegs
Respuestas:
192
Parece haber entendido mal cómo funciona la definición de clases de caracteres en expresiones regulares.
Para que coincida con cualquiera de las cadenas 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, o 12, algo así como funciona esto:
Rangos numéricos (tenga muchos ejemplos de cadenas coincidentes interpretadas como rangos numéricos)
Explicación
Una clase de caracteres, por sí misma, intenta hacer coincidir uno y exactamente un carácter de la cadena de entrada. [01-12]en realidad define [012], una clase de caracteres que coincide con un carácter de la entrada en contra de cualquiera de los 3 personajes 0, 1o 2.
La -definición de rango va de 1a 1, que incluye solo 1. Por otro lado, algo así como [1-9]incluye 1, 2, 3, 4, 5, 6, 7, 8, 9.
Los principiantes suelen cometer errores al definir cosas como [this|that]. Esto no "funciona". Este carácter define definición [this|a], es decir, coincide con un carácter de la entrada contra cualquiera de 6 caracteres t, h, i, s, |o a. Más que probable (this|that)es lo que se pretende.
Entonces es obvio ahora que un patrón como between [24-48] hoursno "funciona". La clase de carácter en este caso es equivalente a [248].
Es decir, -en una clase de caracteres, la definición no define un rango numérico en el patrón. Los motores de expresiones regulares no "comprenden" realmente los números en el patrón, con la excepción de la sintaxis de repetición finita (por ejemplo, a{3,5}coincidencias entre 3 y 5 a).
En su lugar, la definición de rango utiliza codificación ASCII / Unicode de los caracteres para definir rangos. El carácter 0está codificado en ASCII como decimal 48; 9es 57. Por lo tanto, la definición de carácter [0-9]incluye todos los caracteres cuyos valores están entre el decimal 48 y 57 en la codificación. En vez con sensatez, por diseño Estos son los personajes 0, 1, ..., 9.
Para mí, estuve buscando meses sin prefijar 0 si es de un solo dígito. Y usé esto ([1-9] | (1 [0-2])) y funciona.
bunjeeb
2
Es importante tener en cuenta: si encuentra que esta página desea una solución para su rango de números que solo tiene un solo dígito antes de llegar a las decenas, 0[1-9]|1[0-2]no funcionará. Si lo cambia al siguiente paso lógico [1-9]|1[0-2]no funciona, ya sea por razones comprensibles (Coincide con el 1sólo en 10, 11y 12). Tuve que usar \b(?:[0-9]|1[0-1])\bpara evitar eso. \b's se asegura de que la expresión regular coincida con los límites de la palabra (o en este caso el número) ( ^& $no); los corchetes hacen que o ( |) consideren el otro lado; y finalmente ?:es no crear una subcoincidencia con el uso de los corchetes.
user66001
@polygenelubricants: "1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )¿Puede decirme por qué esta expresión regular JS coincide con 17?
edam
@edam - polygenelubricants podrían, por lo que podrían I, pero entonces estaríamos respondiendo a un questi ... espera ... ¿es una cuestión que está pidiendo en un comentario ? Hay rulez en este sitio;) Haga una pregunta si tiene una nueva pregunta. Los comentarios son solo para criticar y pedir aclaraciones, y para responder a ellos.
robinCTS
1
@edam Oh, ya veo. Usted hizo re-pregunta como una pregunta de una hora más tarde. ¡Eso es genial! Sin embargo, probablemente sería una buena idea eliminar su comentario aquí.
robinCTS
24
Una clase de caracteres en expresiones regulares, denotada por la [...]sintaxis, especifica las reglas para hacer coincidir un solo carácter en la entrada. Como tal, todo lo que escribe entre corchetes especifica cómo hacer coincidir un solo carácter .
Su patrón, por [01-12]lo tanto , se desglosa de la siguiente manera:
0 - coincide con el dígito 0
o, 1-1, coincidir con un solo dígito en el rango de 1 a 1
o, 2, coincidir con un solo dígito 2
Entonces, básicamente, todo lo que estás haciendo coincidir es 0, 1 o 2.
Para hacer la coincidencia que desee, haciendo coincidir dos dígitos, que van del 01 al 12 como números, debe pensar en cómo se verán como texto.
Tienes:
01-09 (es decir, el primer dígito es 0, el segundo dígito es 1-9)
10-12 (es decir, el primer dígito es 1, el segundo dígito es 0-2)
Luego tendrá que escribir una expresión regular para eso, que puede verse así:
+-- a 0 followed by1-9||+-- a 1 followed by0-2||<-+--><-+-->0[1-9]|1[0-2]^|+-- vertical bar,this roughly means "OR"inthis context
Tenga en cuenta que intentar combinarlos para obtener una expresión más corta fallará, al dar coincidencias falsas positivas para una entrada no válida.
Por ejemplo, el patrón [0-1][0-9]básicamente coincidiría con los números 00-19, que es un poco más de lo que desea.
Intenté encontrar una fuente definida para obtener más información sobre las clases de personajes, pero por ahora todo lo que puedo darte es esta Consulta de Google para clases de personajes Regex . Con suerte, podrá encontrar más información allí para ayudarlo.
Para ser exactos, [0-1][0-2]también coincide 00. Dicho esto, +1 para el enlace (que he usado en mi respuesta).
polygenelubricants
2
[0-1][0-2]debe interpretarse con cuidado, ya que permite cadenas como 00, 01y 02, pero no admite 03hasta 09, admitiendo finalmente 10, 11y 12. Una expresión regular correcta para eso es [1-9]|1[0-2], o incluso 0*([1-9]|1[0-2])(esta última permite cualquier número de ceros iniciales).
Luis Colorado
1
La []s en una expresión regular denota una clase de carácter . Si no se especifican rangos, implícitamente o todos los caracteres dentro de él juntos. Por lo tanto, [abcde]es igual que (a|b|c|d|e), excepto que no captura nada; que coincidirá con cualquiera de a, b, c, d, o e. Todo lo que indica un rango es un conjunto de caracteres ; [ac-eg]dice "coincidir con cualquiera de a:; cualquier carácter entre cy e; o g". Por lo tanto, su coincidencia dice "coincidir con cualquiera de 0:; cualquier carácter entre 1y 1( es decir , solo 1); o 2.
Evidentemente, su objetivo es especificar un rango de números: cualquier número entre 01y 12escrito con dos dígitos. En este caso específico, puede emparejarlo con 0[1-9]|1[0-2]: a 0seguido de cualquier dígito entre 1y 9, o 1seguido de cualquier dígito entre 0y 2. En general, puede transformar cualquier rango de números en una expresión regular válida de manera similar. Sin embargo, puede haber una opción mejor que las expresiones regulares o una función o módulo existente que pueda construir la expresión regular para usted. Depende de tu idioma.
Como dice Polygenelubricants, el suyo buscaría 0 | 1-1 | 2 en lugar de lo que desea, debido al hecho de que las clases de caracteres (cosas en []) coinciden con caracteres en lugar de cadenas.
[a-z0-9]
esto coincide con todas las letras minúsculas y todos los dígitos, pero solo como un solo carácter.\d+
patrón, 2.) convertir las cadenas coincidentes en números en su código. y luego, 3.) verifique el rango de números comoif(num >= 0 && num <= 12){ /*do something*/ }
. Es mucho más rápido y flexible.Respuestas:
Parece haber entendido mal cómo funciona la definición de clases de caracteres en expresiones regulares.
Para que coincida con cualquiera de las cadenas
01
,02
,03
,04
,05
,06
,07
,08
,09
,10
,11
, o12
, algo así como funciona esto:Referencias
Explicación
Una clase de caracteres, por sí misma, intenta hacer coincidir uno y exactamente un carácter de la cadena de entrada.
[01-12]
en realidad define[012]
, una clase de caracteres que coincide con un carácter de la entrada en contra de cualquiera de los 3 personajes0
,1
o2
.La
-
definición de rango va de1
a1
, que incluye solo1
. Por otro lado, algo así como[1-9]
incluye1
,2
,3
,4
,5
,6
,7
,8
,9
.Los principiantes suelen cometer errores al definir cosas como
[this|that]
. Esto no "funciona". Este carácter define definición[this|a]
, es decir, coincide con un carácter de la entrada contra cualquiera de 6 caracterest
,h
,i
,s
,|
oa
. Más que probable(this|that)
es lo que se pretende.Referencias
Cómo se definen los rangos
Entonces es obvio ahora que un patrón como
between [24-48] hours
no "funciona". La clase de carácter en este caso es equivalente a[248]
.Es decir,
-
en una clase de caracteres, la definición no define un rango numérico en el patrón. Los motores de expresiones regulares no "comprenden" realmente los números en el patrón, con la excepción de la sintaxis de repetición finita (por ejemplo,a{3,5}
coincidencias entre 3 y 5a
).En su lugar, la definición de rango utiliza codificación ASCII / Unicode de los caracteres para definir rangos. El carácter
0
está codificado en ASCII como decimal 48;9
es 57. Por lo tanto, la definición de carácter[0-9]
incluye todos los caracteres cuyos valores están entre el decimal 48 y 57 en la codificación. En vez con sensatez, por diseño Estos son los personajes0
,1
, ...,9
.Ver también
Otro ejemplo: de la A a la Z
Echemos un vistazo a otra definición de clase de carácter común
[a-zA-Z]
En ASCII:
A
= 65,Z
= 90a
= 97,z
= 122Esto significa que:
[a-zA-Z]
y[A-Za-z]
son equivalentes[a-Z]
es probable que sea un rango de caracteres ilegal.a
(97) es "mayor que" queZ
(90)[A-z]
es legal, pero también incluye estos seis caracteres:[
(91),\
(92),]
(93),^
(94),_
(95),`
(96)Preguntas relacionadas
fuente
0[1-9]|1[0-2]
no funcionará. Si lo cambia al siguiente paso lógico[1-9]|1[0-2]
no funciona, ya sea por razones comprensibles (Coincide con el1
sólo en10
,11
y12
). Tuve que usar\b(?:[0-9]|1[0-1])\b
para evitar eso.\b
's se asegura de que la expresión regular coincida con los límites de la palabra (o en este caso el número) (^
&$
no); los corchetes hacen que o (|
) consideren el otro lado; y finalmente?:
es no crear una subcoincidencia con el uso de los corchetes."1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )
¿Puede decirme por qué esta expresión regular JS coincide con 17?Una clase de caracteres en expresiones regulares, denotada por la
[...]
sintaxis, especifica las reglas para hacer coincidir un solo carácter en la entrada. Como tal, todo lo que escribe entre corchetes especifica cómo hacer coincidir un solo carácter .Su patrón, por
[01-12]
lo tanto , se desglosa de la siguiente manera:Entonces, básicamente, todo lo que estás haciendo coincidir es 0, 1 o 2.
Para hacer la coincidencia que desee, haciendo coincidir dos dígitos, que van del 01 al 12 como números, debe pensar en cómo se verán como texto.
Tienes:
Luego tendrá que escribir una expresión regular para eso, que puede verse así:
Tenga en cuenta que intentar combinarlos para obtener una expresión más corta fallará, al dar coincidencias falsas positivas para una entrada no válida.
Por ejemplo, el patrón
[0-1][0-9]
básicamente coincidiría con los números 00-19, que es un poco más de lo que desea.Intenté encontrar una fuente definida para obtener más información sobre las clases de personajes, pero por ahora todo lo que puedo darte es esta Consulta de Google para clases de personajes Regex . Con suerte, podrá encontrar más información allí para ayudarlo.
fuente
Esto también funciona:
^([1-9]|[0-1][0-2])$
[1-9]
coincide con dígitos de un solo dígito entre 1 y 9[0-1][0-2]
coincide con dígitos dobles entre 10 y 12Hay algunos buenos ejemplos aquí.
fuente
[0-1][0-2]
también coincide00
. Dicho esto, +1 para el enlace (que he usado en mi respuesta).[0-1][0-2]
debe interpretarse con cuidado, ya que permite cadenas como00
,01
y02
, pero no admite03
hasta09
, admitiendo finalmente10
,11
y12
. Una expresión regular correcta para eso es[1-9]|1[0-2]
, o incluso0*([1-9]|1[0-2])
(esta última permite cualquier número de ceros iniciales).La
[]
s en una expresión regular denota una clase de carácter . Si no se especifican rangos, implícitamente o todos los caracteres dentro de él juntos. Por lo tanto,[abcde]
es igual que(a|b|c|d|e)
, excepto que no captura nada; que coincidirá con cualquiera dea
,b
,c
,d
, oe
. Todo lo que indica un rango es un conjunto de caracteres ;[ac-eg]
dice "coincidir con cualquiera dea
:; cualquier carácter entrec
ye
; og
". Por lo tanto, su coincidencia dice "coincidir con cualquiera de0
:; cualquier carácter entre1
y1
( es decir , solo1
); o2
.Evidentemente, su objetivo es especificar un rango de números: cualquier número entre
01
y12
escrito con dos dígitos. En este caso específico, puede emparejarlo con0[1-9]|1[0-2]
: a0
seguido de cualquier dígito entre1
y9
, o1
seguido de cualquier dígito entre0
y2
. En general, puede transformar cualquier rango de números en una expresión regular válida de manera similar. Sin embargo, puede haber una opción mejor que las expresiones regulares o una función o módulo existente que pueda construir la expresión regular para usted. Depende de tu idioma.fuente
Como dice Polygenelubricants, el suyo buscaría 0 | 1-1 | 2 en lugar de lo que desea, debido al hecho de que las clases de caracteres (cosas en []) coinciden con caracteres en lugar de cadenas.
fuente
0|1-1|2
- esta notación es muy engañosa. Algo como0|1|2
sería más preciso.Utilizar este:
Para probar un patrón como 07/2018 use esto:
(Rango de fecha entre 01/2000 y 12/9999)
fuente