2009-08-18 51 views
6

necesito una expresión regular para obtener los valores numéricos que pueden serexpresiones regulares para analizar los números de coma flotante internacionales

111.111,11 

111,111.11 

111,111 

y separar las porciones de números enteros y decimales para que pueda almacenar en una base de datos con la sintaxis correcta

me trataron ([0-9]{1,3}[,.]?)+([,.][0-9]{2})? sin éxito, ya que no detecta la segunda parte :(

el resultado debe ser similar:

111.111,11 -> $1 = 111111; $2 = 11 
+0

solo por curiosidad, ¿por qué alguna vez tendrías un patrón como: 11.111.111, que es el reverso del valor real (111,111.11) – ennuikiller

+0

Solo para hacer esta prueba de idiotas. Para que los usuarios no tengan que recordar cuál es el patrón correcto – LuRsT

+0

Eso es realmente bastante inteligente, ya que hay muchos países en el mundo que usan la coma como un separador decimal. Para obtener una lista, consulte aquí: http://en.wikipedia.org/wiki/Decimal_separator#Countries_using_Arabic_numerals_with_decimal_comma –

Respuesta

9

Primera Respuesta:

Esto coincide con #,###,##0.00:

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

Y esto coincide con #.###.##0,00:

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

que une los dos (hay formas más inteligentes/cortos de escribirlo, pero funciona):

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

También puede agregar un grupo de captura a la última coma (o punto) para verificar cuál se utilizó.


Segunda respuesta:

Como se señaló por Alan M, mi solución anterior podía dejar de rechazar un valor como 11,111111.00 donde falta una coma, pero el otro no lo es. Después de algunas pruebas llegué a la siguiente expresión regular que evita este problema:

^[+-]?[0-9]{1,3} 
(?:(?<comma>\,?)[0-9]{3})? 
(?:\k<comma>[0-9]{3})* 
(?:\.[0-9]{2})?$ 

Esto merece alguna explicación:

  • ^[+-]?[0-9]{1,3} coincide con la primera (1 a 3) dígitos;

  • (?:(?<comma>\,?)[0-9]{3})? coincide en una coma opcional seguida de más de 3 dígitos, y captura la coma (o la inexistencia de una) en un grupo llamado 'coma';

  • (?:\k<comma>[0-9]{3})* coincide con cero-a-cualquier repetición de la coma utilizada anteriormente (si la hay) seguida de 3 dígitos;

  • (?:\.[0-9]{2})?$ coincide con "centavos" opcionales al final de la cadena.

Por supuesto, que sólo cubrirá #,###,##0.00 (no #.###.##0,00), pero siempre se puede unirse a las expresiones regulares como lo hice anteriormente.


respuesta final:

Ahora, una solución completa. Las sangrías y los saltos de línea están ahí para la legibilidad solamente.

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

Y esta variación captura los separadores utilizados:

^[+-]?[0-9]{1,3} 
(?: 
    (?:(?<thousand>\,)[0-9]{3})* 
    (?:(?<decimal>\.)[0-9]{2})? 
| 
    (?:(?<thousand>\.)[0-9]{3})* 
    (?:(?<decimal>\,)[0-9]{2})? 
| 
    [0-9]* 
    (?:(?<decimal>[\.\,])[0-9]{2})? 
)$ 

editar 1: "centavos" ahora son opcionales; editar 2: texto agregado; editar 3: segunda solución agregada; edit 4: solución completa agregada; editar 5: encabezados agregados; editar 6: captura añadida; editar 7: la última respuesta se rompió en dos versiones;

+0

+1. Movería los anclajes fuera de la alternancia. También podría mover los elementos comunes de entrada y salida fuera de él, pero eso no vale necesariamente la compensación en legibilidad –

+0

La legibilidad no es un punto fuerte de expresiones regulares, pero estoy de acuerdo. Gracias por el voto :) – jpbochi

+0

Recién notado, los separadores de miles deberían * no * ser opcionales; por ejemplo, '(?: \.? [0-9] {3}) *' debe ser '(?: \. [0-9] {3}) *'. De lo contrario, podría hacer coincidir cosas como '11,111111.00' o' 1111.111,00'. –

1

¿Qué tal

/(\d{1,3}(?:,\d{3})*)(\.\d{2})?/ 

si se preocupan por la validación de que las comas separan cada 3 dígitos exactamente, o

/(\d[\d,]*)(\.\d{2})?/ 

si no lo hace.

+0

Esto no validará su primer ejemplo; 111.111,11 –

+0

Es cierto. No me di cuenta de eso. Lo siento. – Avi

0

Si estoy interpretando su pregunta correctamente para que diga que el resultado DEBE parecerse a lo que dice que "sería", entonces creo que solo debe dejar la coma fuera de la clase de caracteres, ya que se usa como separador y no como parte de lo que se debe igualar.

Así que deshazte de la "." primero, luego unir las dos partes.

$value = "111,111.11"; 
$value =~ s/\.//g; 
$value =~ m/(\d+)(?:,(\d+))?/; 

$ 1 = principales enteros con períodos removidos $ 2 = undef ya sea si no existiera, o el post-coma dígitos si los hay.

3

Me gustaría en el primer uso esta expresión regular para determinar wether una coma o un punto se utiliza como un delimitador de coma (Se obtiene el último de los dos):

[0-9,\.]*([,\.])[0-9]* 

Me gustaría entonces despojar todos los demás signo (que el anterior no coincide). Si no hubo coincidencias, ya tiene un número entero y puede omitir los siguientes pasos. La eliminación del signo elegido se puede hacer fácilmente con una expresión regular, pero también hay muchas otras funciones que pueden hacer esto más rápido/mejor.

Le quedan un número en forma de un entero posible seguido de una coma o un punto y luego los decimales, donde la parte entera y la decimal se pueden separar fácilmente entre sí con la siguiente expresión regular.

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

¡Buena suerte!

Editar:

Aquí es un ejemplo realizado en Python, que supongo que el código debe ser auto-explica, si no está, sólo hay que preguntar.

import re 

input = str(raw_input()) 
delimiterRegex = re.compile('[0-9,\.]*([,\.])[0-9]*') 
splitRegex = re.compile('([0-9]+)[,\.]?([0-9]*)') 

delimiter = re.findall(delimiterRegex, input) 

if (delimiter[0] == ','): 
    input = re.sub('[\.]*','', input) 
elif (delimiter[0] == '.'): 
    input = re.sub('[,]*','', input) 

print input 

Con este código, las siguientes entradas da esto:

  • 111.111,11

    111111,11

  • 111,111.11

    111111,11

  • 111.111

    111.111

Después de este paso, ahora se puede modificar fácilmente la cadena para que coincida con sus necesidades.

+0

Estoy bastante seguro de que esta respuesta es incorrecta, pero no puedo decirlo con certeza porque realmente no dice cómo está usando las expresiones regulares (pero eso es motivo suficiente para un voto negativo allí). ¿Puede explicar cómo está distinguiendo el separador de miles del separador decimal (con ejemplos probados)? –

+0

La primera expresión regular determinará cuál es el separador decimal al encontrar cuál de ellos ocurre último. Luego quita el número del otro operador. Y te quedarás con un número sin miles de separadores. El resto debería ser pan comido. Publicará código de ejemplo más tarde. –

+0

Según el OP, la coma en '111,111' es un separador de miles (TS). Un separador decimal (DS), si está presente, debe ir seguido de exactamente dos dígitos (aclaró eso en los comentarios de la pregunta). ¿Entonces su primera expresión regular debería terminar con '([,.] [0-9] {2})?' Como lo hicieron los OP. Pero también está tratando de validar que los TS están distribuidos correctamente. –

Cuestiones relacionadas