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
[+-]?([0-9]*[.])?[0-9]+
Esto coincidirá con:
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:
[+-]?([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 $
, así:
^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$
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:
// creates a single character string: "\"
String x = "\\";
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:
// 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 invertida en el lenguaje en el que está programando:
// will most likely result in an "Illegal escape character" error
String wrongPattern = "\.";
// will result in the string "\."
String correctPattern = "\\.";
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:
String correctPattern = "[.]";
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+
[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 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:
\d+
Ahora queremos agregar la parte decimal, pero no va donde cree que podría:
\d+\.?\d* /* This isn't quite correct. */
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:
\d+(\.\d+)? /* Better. But... */
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:
(\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 formato largo:
[+-]?([0-9]*[.])?[0-9]+
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:
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, "ajuste" la expresión al inicio y al final de la entrada envolviéndola en etiquetas de anclaje:
^[+-]?([0-9]*[.])?[0-9]+$
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, pero apple 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, devolviendo true
si se encuentra una coincidencia y false
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.