Expresión regular para números de coma flotante

Tengo una tarea para hacer coincidir los números de coma flotante. He escrito la siguiente expresión regular para ello:

[-+]?[0-9]*\.?[0-9]* 

Pero muestra un error que dice:

 Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ ) 

Pero según mi conocimiento, necesitamos usar un personaje de escape para el . además. Por favor, corrígeme donde estoy equivocado.

TL; DR

Use [.] lugar de \. y [0-9] lugar de \d para evitar problemas de escape en algunos idiomas (como Java).

Un patrón relativamente simple para hacer coincidir un número de punto flotante es

 [+-]?([0-9]*[.])?[0-9]+ 

Esto coincidirá:

  • 123
  • 123.456
  • .456

Ver un ejemplo de trabajo

Si también desea hacer coincidir 123. (un período sin parte decimal), necesitará una expresión un poco más larga:

 [+-]?([0-9]+([.][0-9]*)?|[.][0-9]+) 

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 $ , como sigue:

 ^[+-]?([0-9]*[.])?[0-9]+$ 

Expresiones regulares irregulares

Las “expresiones regulares”, tal como se implementan en la mayoría de los lenguajes modernos, API, marcos, 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 más allá de la definición formal. Entonces, aunque la mayoría de los motores de expresiones regulares se parecen entre sí, en realidad no existe un estándar. Por este motivo, mucho depende de qué idioma, API, marco o biblioteca esté utilizando.

(Por cierto, para ayudar a reducir la confusión, muchos han comenzado a utilizar ” regex ” o ” regexp ” para describir estos idiomas mejorados coincidentes. Consulte ¿Es Regex 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 ellos, hasta donde yo sé) aceptarían \. . Lo más probable es que haya un problema con el escape.

El problema de escapar

(Gracias a la sin nombre por reconocer originalmente esto).

Algunos idiomas 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ás codificando en un idioma dentro de un idioma. Java, por ejemplo, usa \ como un carácter de escape dentro de sus cadenas, por lo que si desea colocar un carácter literal de barra invertida dentro de una cadena, debe escapar de él:

 // creates a single character string: "\" String x = "\\"; 

Sin embargo, las expresiones regulares también usan el carácter \ para escaparse, por lo que si desea hacer coincidir un carácter literal \ , debe escaparlo para el motor de generación de regex y luego volver a escaparlo para Java:

 // Creates a two-character string: "\\" // When used as a regex pattern, will match a single character: "\" String regexPattern = "\\\\"; 

En su caso, probablemente no haya escapado del carácter de barra diagonal inversa en el idioma en el que está progtwigndo:

 // will most likely result in an "Illegal escape character" error String wrongPattern = "\."; // will result in the string "\." String correctPattern = "\\."; 

Todo este escape puede ser muy confuso. Si el idioma con el que está trabajando admite cadenas sin formato , entonces debe usarlas para reducir el número de barras diagonales inversas, pero no todos los idiomas (más notablemente: Java). Afortunadamente, hay una alternativa que funcionará algunas veces:

 String correctPattern = "[.]"; 

Para un motor de expresiones regulares, \. y [.] significan exactamente lo mismo. Tenga en cuenta que esto no funciona en todos los casos, como nueva línea ( \\n ), abrir corchete ( \\[ ) y barra invertida ( \\\\ o [\\] ).

Una nota sobre los números coincidentes

(Sugerencia: es más difícil de lo que piensas)

Coincidir un número es una de esas cosas que pensarías que es bastante fácil con regex, pero en realidad es bastante complicado. Echemos un vistazo a su enfoque, pieza por pieza:

 [-+]? 

Coincide con un opcional - o +

 [0-9]* 

Coincide con 0 o más dígitos secuenciales

 \.? 

Coincide con un opcional .

 [0-9]* 

Coincide con 0 o más dígitos secuenciales

Primero, podemos limpiar esta expresión un poco usando una taquigrafía 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 \d continuación, pero tenga en cuenta que significa lo mismo que [0-9] . (Bueno, en realidad, en algunos motores \d coincidirá con los dígitos de todos los scripts, por lo que coincidirá con más de [0-9] voluntad, pero eso probablemente no es significativo en su caso.)

Ahora, si miras detenidamente esto, te darás cuenta de que cada parte de tu patrón es opcional . Este patrón puede coincidir con una cadena de 0 de longitud; una cadena compuesta solo de + o - ; o, una cuerda compuesta solo de a . . Probablemente esto no sea lo que pretendías.

Para solucionar esto, es útil comenzar por “anclar” su expresión regular con la cadena requerida mínima, probablemente un solo dígito:

 \d+ 

Ahora queremos agregar la parte decimal, pero no va a donde crees que podría:

 \d+\.?\d* /* This isn't quite correct. */ 

Esto aún coincidirá con valores como 123. .. Peor aún, tiene un poco de maldad al respecto. El período es opcional, lo que significa que tiene dos clases repetidas una al lado de la otra ( \d+ y \d* ). Esto realmente puede ser peligroso si se usa de la manera incorrecta, abriendo su sistema a ataques DoS.

Para solucionar esto, en lugar de tratar el período como opcional, debemos tratarlo como sea necesario (para separar las clases de caracteres repetidos) y, en cambio, hacer que la porción decimal entera sea opcional:

 \d+(\.\d+)? /* Better. But... */ 

Esto se ve mejor ahora. Necesitamos un período entre la primera secuencia de dígitos y el segundo, pero hay un defecto fatal: no podemos hacer coincidir .123 porque ahora se requiere un dígito .123 .

Esto es realmente bastante fácil de arreglar. En lugar de hacer que la porción “decimal” del número sea opcional, necesitamos verlo como una secuencia de caracteres: 1 o más números que pueden estar precedidos por a . que puede estar precedido por 0 o más números:

 (\d*\.)?\d+ 

Ahora solo agregamos el signo:

 [+-]?(\d*\.)?\d+ 

Por supuesto, esas barras son bastante molestas en Java, por lo que podemos sustituirlas en nuestras clases de caracteres de forma larga:

 [+-]?([0-9]*[.])?[0-9]+ 

Emparejamiento versus Validación

Esto ha aparecido en los comentarios un par de veces, así que estoy agregando un apéndice sobre la comparación versus la validación.

El objective de la coincidencia es encontrar algún contenido dentro de la entrada (la “aguja en un pajar”). El objective de la validación es garantizar que la entrada se encuentre en un formato esperado.

Regexes, por su naturaleza, solo coinciden con el texto. Dadas algunas entradas, encontrarán algún texto que coincida o no lo harán. Sin embargo, al “ajustar” una expresión al principio y al final de la entrada con tags de anclaje ( ^ y $ ), podemos asegurarnos de que no se encuentre ninguna coincidencia a menos que toda la entrada coincida con la expresión, utilizando 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 objective. Entonces, dada la entrada:

 apple 1.34 pear 7.98 version 1.2.3.4 

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, “ajusta” la expresión al inicio y al final de la entrada envolviéndola en tags de anclaje:

 ^[+-]?([0-9]*[.])?[0-9]+$ 

Esto solo encontrará una coincidencia si la entrada completa 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, pero dada apple 1.2 pear no se encontrarán coincidencias.

Tenga en cuenta que algunos motores de isMatch regulares tienen una función validate , isMatch o similar, que básicamente hace lo que he descrito automáticamente, devuelve true si se encuentra una coincidencia y false si no se encuentra coincidencia. También tenga en cuenta que algunos motores le permiten establecer indicadores que cambian la definición de ^ y $ , que coincide con el comienzo / final de una línea en lugar del comienzo / final de la entrada completa. Por lo general, esto no es lo predeterminado, pero esté atento a estos indicadores.

No creo que ninguna de las respuestas en esta página al momento de escribir sean correctas (también muchas otras sugerencias en SO también están equivocadas). La complicación es que debe hacer coincidir todas las siguientes posibilidades:

  • Sin punto decimal (es decir, un valor entero)
  • Dígitos tanto antes como después del punto decimal (p. Ej., 0.35 , 22.165 )
  • Dígitos antes del punto decimal solamente (por ejemplo, 0. , 1234. )
  • Dígitos después del punto decimal solamente (p. Ej., .5678 , .5678 )

Al mismo tiempo, debe asegurarse de que haya al menos un dígito en alguna parte, es decir, no se permite lo siguiente:

  • un punto decimal por sí mismo
  • un punto decimal firmado sin dígitos (es decir, +. o -. )
  • + o - por su propia cuenta
  • una cadena vacía

Esto parece complicado al principio, pero una forma de encontrar inspiración es mirar el código fuente de OpenJDK para el método java.lang.Double.valueOf(String) (comience en http://hg.openjdk.java.net/jdk8/jdk8 / jdk , haga clic en “explorar”, navegue hacia abajo /src/share/classes/java/lang/ y busque la clase Double ). La expresión regular larga que contiene esta clase abarca diversas posibilidades que probablemente el OP no tenía en mente, pero ignora por simplicidad las partes que tratan con NaN, infinito, notación hexadecimal y exponentes, y usa \d lugar de POSIX. notación para un solo dígito, puedo reducir las partes importantes de la expresión regular para un número de punto flotante con signo sin exponente para:

[+-]?((\d+\.?\d*)|(\.\d+))

No creo que haya una forma de evitar la construcción (...)|(...) sin permitir algo que no contenga ningún dígito, o prohibir una de las posibilidades que no tiene dígitos antes del punto decimal o sin dígitos después de.

Obviamente, en la práctica tendrá que ocuparse de los espacios en blanco anteriores o anteriores, ya sea en la expresión regular o en el código que la utiliza.

lo que necesitas es:

 [\-\+]?[0-9]*(\.[0-9]+)? 

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:

 0 +1 -2.0 2.23442 

Esto es simple: has usado Java y deberías usar \\. en lugar de \. (búsqueda del carácter que escapa en Java).

Este trabajó para mí:

 (?P[-+]*\d+\.\d+|[-+]*\d+) 

También puede usar este (sin parámetro nombrado):

 ([-+]*\d+\.\d+|[-+]*\d+) 

Use algún probador de expresiones regulares en línea para probarlo (p. Ej., Regex101)

 [+-]?(([1-9][0-9]*)|(0))([.,][0-9]+)? 

[+-]? – Signo principal opcional

(([1-9][0-9]*)|(0)) – entero sin cero inicial, incluido el cero individual

([.,][0-9]+)? – parte fraccional opcional

 ^[+]?([0-9]{1,2})*[.,]([0-9]{1,1})?$ 

Esto coincidirá:

  1. 1.2
  2. 12.3
  3. 1,2
  4. 12,3
 [+/-] [0-9]*.[0-9]+ 

Prueba esta solución

para javascript

 const test = new RegExp('^[+]?([0-9]{0,})*[.]?([0-9]{0,2})?$','g'); 

Lo cual funcionaría para 1.23 1234.22 0 0.12 12

Puede cambiar las partes en {} para obtener resultados diferentes en la longitud decimal y el frente del decimal también. Esto se usa en las entradas para ingresar un número y verificar cada entrada a medida que escribe, permitiendo solo lo que pasa.