Tengo una tarea para hacer coincidir números de punto flotante. He escrito la siguiente expresión regular para ello:
[-+]?[0-9]*\.?[0-9]*
Pero devuelve un error:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )
Según mi conocimiento, necesitamos usar un carácter de escape para .
también. Por favor, corríjame donde me equivoque.
(?:\d+(?:\.\d*)?|\.\d+)
y se ha publicado ad infinitum en SO ...[-+]?([0-9]*[.])?[0-9]+([eE][-+]?\d+)?
si también desea captar la notación exponencial, e, g, 3.023e-23Respuestas:
TL; DR
Úselo en
[.]
lugar de\.
y en[0-9]
lugar de\d
para evitar problemas de escape en algunos lenguajes (como Java).Gracias al sin nombre por reconocer esto originalmente.
Un patrón relativamente simple para hacer coincidir un número de punto flotante es
Esto coincidirá con:
123
123.456
.456
Ver un ejemplo funcional
Si también desea hacer coincidir
123.
(un período sin parte decimal), necesitará una expresión un poco más larga:Vea la respuesta de pkeller para una explicación más completa de este patrón
Si desea incluir números no decimales, como hexadecimal y octal, consulte mi respuesta a ¿Cómo identifico si una cadena es un número? .
Si desea validar que una entrada es un número (en lugar de encontrar un número dentro de la entrada), entonces debe rodear el patrón con
^
y$
, así:Expresiones regulares irregulares
Las "expresiones regulares", tal como se implementan en la mayoría de los lenguajes, API, frameworks, bibliotecas, etc., se basan en un concepto desarrollado en la teoría del lenguaje formal . Sin embargo, los ingenieros de software han agregado muchas extensiones que llevan estas implementaciones mucho más allá de la definición formal. Entonces, aunque la mayoría de los motores de expresión regular se parecen entre sí, en realidad no existe un estándar. Por esta razón, mucho depende del lenguaje, API, marco o biblioteca que esté utilizando.
(Por cierto, para ayudar a reducir la confusión, muchos han comenzado a usar " regex " o " regexp " para describir estos idiomas de coincidencia mejorados. Consulte ¿Es una expresión regular lo mismo que una expresión regular? En RexEgg.com para obtener más información).
Dicho esto, la mayoría de los motores de expresiones regulares (en realidad, todos, hasta donde yo sé) aceptarían
\.
. Lo más probable es que haya un problema para escapar.El problema de escapar
Algunos lenguajes tienen soporte integrado para expresiones regulares, como JavaScript . Para aquellos idiomas que no lo hacen, escapar puede ser un problema.
Esto se debe a que básicamente está codificando en un idioma dentro de otro idioma. Java, por ejemplo, se usa
\
como carácter de escape dentro de sus cadenas, por lo que si desea colocar un carácter de barra invertida literal dentro de una cadena, debe escapar de él:Sin embargo, las expresiones regulares también usan el
\
carácter para escapar, por lo que si desea hacer coincidir un\
carácter literal , debe escaparlo para el motor de expresiones regulares y luego escaparlo nuevamente para Java:En su caso, probablemente no haya escapado del carácter de barra invertida en el lenguaje en el que está programando:
Todo este escape puede resultar muy confuso. Si el lenguaje con el que está trabajando admite cadenas sin formato , entonces debería usarlas para reducir el número de barras invertidas, pero no todos los lenguajes lo hacen (más notablemente: Java). Afortunadamente, existe una alternativa que funcionará algunas veces:
Para un motor de expresiones regulares,
\.
y[.]
significa exactamente lo mismo. Tenga en cuenta que esto no funciona en todos los casos, como nueva línea (\\n
), corchete abierto (\\[
) y barra invertida (\\\\
o[\\]
).Una nota sobre la coincidencia de números
(Pista: es más difícil de lo que piensas)
Hacer coincidir un número es una de esas cosas que pensaría que es bastante fácil con expresiones regulares, pero en realidad es bastante complicado. Echemos un vistazo a su enfoque, pieza por pieza:
Coincide con un opcional
-
o+
Coincide con 0 o más dígitos secuenciales
Coincide con un opcional
.
Coincide con 0 o más dígitos secuenciales
Primero, podemos limpiar un poco esta expresión usando una abreviatura de clase de caracteres para los dígitos (tenga en cuenta que esto también es susceptible al problema de escape mencionado anteriormente):
[0-9]
=\d
Voy a usar a
\d
continuación, pero ten en cuenta que significa lo mismo que[0-9]
. (Bueno, en realidad, en algunos motores\d
coincidirán los dígitos de todos los scripts, por lo que coincidirá con más de[0-9]
lo que lo hará, pero eso probablemente no sea significativo en su caso).Ahora, si observa esto detenidamente, se dará cuenta de que cada parte de su patrón es opcional . Este patrón puede coincidir con una cadena de longitud 0; una cadena compuesta solo por
+
o-
; o, una cadena compuesta solo por a.
. Probablemente esto no sea lo que pretendías.Para solucionar esto, es útil comenzar por "anclar" su expresión regular con la cadena mínima requerida, probablemente un solo dígito:
Ahora queremos agregar la parte decimal, pero no va donde cree que podría:
Esto seguirá coincidiendo con valores como
123.
. Peor aún, tiene un matiz de maldad . El período es opcional, lo que significa que tiene dos clases repetidas una al lado de la otra (\d+
y\d*
). En realidad, esto puede ser peligroso si se usa de manera incorrecta, lo que abre su sistema a ataques DoS.Para solucionar este problema, en lugar de tratar el período como opcional, debemos tratarlo como se requiere (para separar las clases de caracteres repetidas) y, en su lugar, hacer que toda la parte decimal sea opcional:
Esto se ve mejor ahora. Requerimos un período entre la primera secuencia de dígitos y el segundo, pero hay un defecto fatal: no podemos coincidir
.123
porque ahora se requiere un dígito inicial.En realidad, esto es bastante fácil de solucionar. En lugar de hacer que la parte "decimal" del número sea opcional, debemos considerarla como una secuencia de caracteres: 1 o más números que pueden tener como prefijo un
.
prefijo con 0 o más números:Ahora solo agregamos el signo:
Por supuesto, esas barras son bastante molestas en Java, por lo que podemos sustituirlas en nuestras clases de caracteres de formato largo:
Coincidencia versus validación
Esto ha aparecido en los comentarios un par de veces, así que estoy agregando un apéndice sobre coincidencia versus validación.
El objetivo de hacer coincidir es encontrar algún contenido dentro de la entrada (la "aguja en un pajar"). El objetivo de la validación es garantizar que la entrada tenga el formato esperado.
Las expresiones regulares, por su naturaleza, solo coinciden con el texto. Dada alguna entrada, encontrarán algún texto coincidente o no. Sin embargo, al "ajustar" una expresión al principio y al final de la entrada con etiquetas de anclaje (
^
y$
), podemos asegurarnos de que no se encuentre ninguna coincidencia a menos que toda la entrada coincida con la expresión, utilizando de manera efectiva expresiones regulares para validar .La expresión regular descrita anteriormente (
[+-]?([0-9]*[.])?[0-9]+
) coincidirá con uno o más números dentro de una cadena de destino. Entonces, dada la entrada:La expresión regular coincidirá con
1.34
,7.98
,1.2
,.3
y.4
.Para validar que una entrada dada es un número y nada más que un número, "ajuste" la expresión al inicio y al final de la entrada envolviéndola en etiquetas de anclaje:
Esto solo encontrará una coincidencia si toda la entrada es un número de punto flotante y no encontrará una coincidencia si la entrada contiene caracteres adicionales. Entonces, dada la entrada
1.2
, se encontrará una coincidencia, peroapple 1.2 pear
no se encontrará ninguna coincidencia.Tenga en cuenta que algunos motores de expresiones regulares tienen una función
validate
,isMatch
o similar, que esencialmente hace lo que he descrito automáticamente, devolviendotrue
si se encuentra una coincidencia yfalse
si no se encuentra ninguna coincidencia. También tenga en cuenta que algunos motores le permiten establecer indicadores que cambian la definición de^
y$
, haciendo coincidir el principio / final de una línea en lugar del principio / final de toda la entrada. Por lo general, este no es el predeterminado, pero esté atento a estas banderas.fuente
\d+(\.\d*)?|\.\d+
/[-+]?(\d*[.])?\d+/.test("1.bc") // returns true
1.
coincide. Agregue^
y$
al principio y al final de la expresión regular si desea hacer coincidir solo si toda la entrada coincide.[-+]?(([0-9]*[.]?[0-9]+([ed][-+]?[0-9]+)?)|(inf)|(nan))
e / d para float / double precisión float. No olvide una bandera de caso plegable a la expresión regularNo creo que ninguna de las respuestas en esta página en el momento de escribir este artículo sea correcta (también muchas otras sugerencias en otros lugares de SO también están equivocadas). La complicación es que debe combinar todas las siguientes posibilidades:
0.35
. Ej. ,22.165
)0.
. Ej. ,1234.
).0
. Ej. ,.5678
)Al mismo tiempo, debe asegurarse de que haya al menos un dígito en alguna parte, es decir, no se permiten los siguientes:
+.
o-.
)+
o-
por su cuentaEsto parece complicado al principio, pero una forma de encontrar inspiración es buscar el
java.lang.Double.valueOf(String)
método en la fuente OpenJDK (comience en http://hg.openjdk.java.net/jdk8/jdk8/jdk , haga clic en "navegar", navegue hacia abajo/src/share/classes/java/lang/
y encuentra laDouble
clase). La expresión regular larga que contiene esta clase cubre varias posibilidades que el OP probablemente no tenía en mente, pero ignorando por simplicidad las partes que tratan con NaN, infinito, notación hexadecimal y exponentes, y usando en\d
lugar de la notación POSIX para un solo dígito, puedo reducir las partes importantes de la expresión regular para un número de punto flotante firmado sin exponente a:[+-]?((\d+\.?\d*)|(\.\d+))
No creo que haya una forma de evitar la
(...)|(...)
construcción sin permitir algo que no contenga dígitos, o prohibir una de las posibilidades que no tenga dígitos antes del punto decimal o sin dígitos después.Obviamente, en la práctica, deberá tener en cuenta los espacios en blanco finales o anteriores, ya sea en la expresión regular o en el código que la usa.
fuente
123.
, entonces sí ... el interruptor o es la única solución, como señalé en un comentario en mi publicación original.[+-]?((?=\.?\d)\d*\.?\d*)
puede usar la expresión regular para evitar la alternancia? Utiliza un lookahead ...lo que necesitas es:
Me escapé del signo "+" y "-" y también agrupé el decimal con sus siguientes dígitos desde algo como "1". No es un número válido.
Los cambios le permitirán hacer coincidir enteros y flotantes. por ejemplo:
fuente
.1
no se permitiría, aunque tal entrada se reconoce universalmente como correcta.-
y+
, que no son números. ¡Regex es complicado! :)\.
no funciona.Quiero hacer coincidir lo que la mayoría de los idiomas consideran números válidos (enteros y flotantes):
'5' / '-5'
'1.0' / '1.' / '.1' / '-1.' / '-.1'
'0.45326e+04', '666999e-05', '0.2e-3', '-33.e-1'
Notas:
preceding sign of number ('-' or '+') is optional
'-1.' and '-.1' are valid but '.' and '-.' are invalid
'.1e3' is valid, but '.e3' and 'e3' are invalid
Para admitir tanto '1'. y '.1' necesitamos un operador OR ('|') para asegurarnos de excluir '.' de emparejar.
[+-]?
+/- cantar es opcional ya que?
significa 0 o 1 coincidencias(
como tenemos 2 subexpresiones, debemos ponerlas entre paréntesis\d+([.]\d*)?(e[+-]?\d+)?
Esto es para números que comienzan con un dígito|
separa subexpresiones[.]\d+(e[+-]?\d+)?
esto es para números que comienzan con '.')
fin de expresiones[.]
el primer carácter es un punto (entre corchetes o de lo contrario es un carácter comodín)\d+
uno o más dígitos(e[+-]?\d+)?
esta es una notación científica opcional (0 o 1 coincidencias debido a la terminación '?')\d+
uno o más dígitos([.]\d*)?
opcionalmente podemos tener un carácter de punto y cero o más dígitos después de él(e[+-]?\d+)?
esta es una notación científica opcionale
literal que especifica exponente[+-]?
signo de exponente opcional\d+
uno o más dígitosTodos los combinados:
Para aceptar
E
también:( Casos de prueba )
fuente
Esto es simple: ha usado Java y debería usar en
\\.
lugar de\.
(buscar caracteres que se escapan en Java).fuente
Este funcionó para mí:
También puede usar este (sin parámetro con nombre):
Use algún probador de expresiones regulares en línea para probarlo (por ejemplo, regex101)
fuente
Esto coincidirá con:
fuente
[+-]?
- señal inicial opcional(([1-9][0-9]*)|(0))
- entero sin cero a la izquierda, incluido un solo cero([.,][0-9]+)?
- parte fraccionaria opcionalfuente
En C ++ usando la biblioteca regex
La respuesta sería así:
Tenga en cuenta que no tomo el símbolo del signo, si lo quisiera con el símbolo del signo, se trataría de esto:
Esto también separa un número regular o un número decimal.
fuente
En notación c, el número flotante puede aparecer en las siguientes formas:
Para crear una expresión regular flotante, primero crearé una "variable de expresión regular int":
Ahora, escribiré pequeños trozos de expresión regular flotante; la solución es concatenar esos trozos con o simbol "|".
Trozos:
Solución final (concanar pequeños trozos):
fuente
Prueba esta solución.
fuente
para javascript
Cuál funcionaría para 1.23 1234.22 0 0.12 12
Puede cambiar las partes en
{}
para obtener diferentes resultados en la longitud decimal y también en el frente del decimal. Esto se usa en entradas para ingresar un número y verificar cada entrada mientras escribe, permitiendo solo lo que pasa.fuente