2011-01-16 5 views
57

Tengo un número de cadenas similar a Current Level: 13.4 db. y me gustaría extraer solo el número de coma flotante. Digo flotante y no decimal, ya que a veces es completo. ¿Puede RegEx hacer esto o hay una mejor manera?Cómo extraer un número flotante de una cadena

+0

¿Será siempre tienen una parte entera? Incluso si es 0? ¿Necesitas igualar 0.4 o .4? – Falmarri

+0

Yo diría que sí. La entrada se ingresa manualmente, por lo que existe la posibilidad de incoherencia. – Flowpoke

Respuesta

112

Si el flotador siempre se expresa en notación decimal algo así como

>>> import re 
>>> re.findall("\d+\.\d+", "Current Level: 13.4 db.") 
['13.4'] 

puede ser suficiente.

Una versión más robusto sería:

>>> re.findall(r"[-+]?\d*\.\d+|\d+", "Current Level: -13.2 db or 14.2 or 3") 
['-13.2', '14.2', '3'] 

Si desea validar la entrada del usuario, que podría ser alternativamente también comprobar si hay un flotador por pisar a él directamente:

user_input = "Current Level: 1e100 db" 
for token in user_input.split(): 
    try: 
     # if this succeeds, you have your (first) float 
     print float(token), "is a float" 
    except ValueError: 
     print token, "is something else" 

# => Would print ... 
# 
# Current is something else 
# Level: is something else 
# 1e+100 is a float 
# db is something else 
+0

no es siempre un número decimal. – Flowpoke

+2

're.findall (r" [- +]? \ D * \. * \ D + "," Nivel actual: -13.2 db o 14.2 o 3 ")' '['-13.2', '14 .2 ',' 3 '] ' – JuanPablo

+1

Creo que quiso decir" \ d + \. \ D + "en lugar de" \ d +. \ D + "en su primer bloque de código. En este momento extraería algo como '13a4'. – abw333

0

Otro enfoque que puede ser más legible es la conversión de tipo simple. He añadido una función de reemplazo para cubrir casos en los que las personas pueden entrar decimales europeas:

>>> for possibility in "Current Level: -13.2 db or 14,2 or 3".split(): 
...  try: 
...   str(float(possibility.replace(',', '.'))) 
...  except ValueError: 
...   pass 
'-13.2' 
'14.2' 
'3.0' 

Esto tiene desventajas, sin embargo. Si alguien escribe "1,000", se convertirá en 1. Además, supone que las personas ingresarán espacios en blanco entre palabras. Este no es el caso con otros idiomas, como el chino.

+0

"pilas 4x tamaño AAA 1.5V incluidas": -) –

+0

¡Esos usuarios terribles! Siempre ingresando datos tontos. TBH, intencionalmente he mantenido este ejemplo demostrativo en lugar de robusto. Cuando comencé a escribir esta respuesta, @The MYYN solo me proporcionó expresiones regulares en la respuesta aceptada. Quería dar un ejemplo de otra forma de hacer las cosas. –

37

Es posible que quiera probar algo como esto, que cubre todas las bases, incluyendo no depender de un espacio en blanco después del número:

>>> import re 
>>> numeric_const_pattern = r""" 
...  [-+]? # optional sign 
...  (?: 
...   (?: \d* \. \d+) # .1 .12 .123 etc 9.1 etc 98.1 etc 
...   | 
...   (?: \d+ \.?) # 1. 12. 123. etc 1 12 123 etc 
... ) 
...  # followed by optional exponent part if desired 
...  (?: [Ee] [+-]? \d+) ? 
...  """ 
>>> rx = re.compile(numeric_const_pattern, re.VERBOSE) 
>>> rx.findall(".1 .12 9.1 98.1 1. 12. 1 12") 
['.1', '.12', '9.1', '98.1', '1.', '12.', '1', '12'] 
>>> rx.findall("-1 +1 2e9 +2E+09 -2e-9") 
['-1', '+1', '2e9', '+2E+09', '-2e-9'] 
>>> rx.findall("current level: -2.03e+99db") 
['-2.03e+99'] 
>>> 

Para una fácil copiar y pegar:

numeric_const_pattern = '[-+]? (?: (?: \d* \. \d+) | (?: \d+ \.?))(?: [Ee] [+-]? \d+) ?' 
rx = re.compile(numeric_const_pattern, re.VERBOSE) 
rx.findall("Some example: Jr. it. was .23 between 2.3 and 42.31 seconds") 
+2

¡Muy bien! ¡Finalmente he encontrado un patrón realmente bueno! –

+0

Sí, el mejor patrón de todos los tiempos. ¡Muchas gracias! – edisonex

+0

Agregar '(?: \ + \ S * | \ - \ s *)?' Al frente también permitiría un espacio entre el signo y el número. Aunque admito que esto probablemente no es muy "estándar", he visto este patrón "flotando" en algunos archivos. – NOhs

5
re.findall(r"[-+]?\d*\.\d+|\d+", "Current Level: -13.2 db or 14.2 or 3") 

como se describió anteriormente, ¡funciona realmente bien! Una sugerencia sin embargo:

re.findall(r"[-+]?\d*\.\d+|[-+]?\d+", "Current Level: -13.2 db or 14.2 or 3 or -3") 

también volverá valores int negativos (como -3 en el final de esta cadena)

2

creo que puede encontrar cosas interesantes en la siguiente respuesta de la mina que me hizo por una cuestión similar anterior:

https://stackoverflow.com/q/5929469/551449

En esta respuesta, he propuesto un modelo que permite una expresión regular para recoger cualquier tipo de número y ya no tengo nada más que añadir a ello, creo es bastante completo

13

Python docs tiene una respuesta que cubre +/-, y la notación exponente

scanf() Token  Regular Expression 
%e, %E, %f, %g  [-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)? 
%i     [-+]?(0[xX][\dA-Fa-f]+|0[0-7]*|\d+) 

Esta expresión regular no soporta formatos internacionales que se utiliza una coma como separador entre el carácter del conjunto y fraccionada parte (3,14159). En ese caso, reemplace todo \. con [.,] en la expresión regular del flotador anterior.

     Regular Expression 
International float  [-+]?(\d+([.,]\d*)?|[.,]\d+)([eE][-+]?\d+)? 
2

Usted puede usar la siguiente expresión regular para obtener valores enteros y flotantes de una cadena:

re.findall(r'[\d\.\d]+', 'hello -34 42 +34.478m 88 cricket -44.3') 

['34', '42', '34.478', '88', '44.3'] 

Gracias Rex

+2

Esta expresión regular también encontrará combinaciones no numéricas de puntos y dígitos: ''.... 1.2.3.4 ..56 ..'' produce: '['....', '1.2.3.4', '. .56 .. '] ' – scottbb

Cuestiones relacionadas