Respuestas:
Si solo desea extraer solo enteros positivos, intente lo siguiente:
>>> str = "h3110 23 cat 444.4 rabbit 11 2 dog"
>>> [int(s) for s in str.split() if s.isdigit()]
[23, 11, 2]
Yo diría que esto es mejor que el ejemplo de expresiones regulares por tres razones. Primero, no necesitas otro módulo; en segundo lugar, es más legible porque no necesita analizar el mini-lenguaje regex; y tercero, es más rápido (y, por lo tanto, probablemente más pitónico):
python -m timeit -s "str = 'h3110 23 cat 444.4 rabbit 11 2 dog' * 1000" "[s for s in str.split() if s.isdigit()]"
100 loops, best of 3: 2.84 msec per loop
python -m timeit -s "import re" "str = 'h3110 23 cat 444.4 rabbit 11 2 dog' * 1000" "re.findall('\\b\\d+\\b', str)"
100 loops, best of 3: 5.66 msec per loop
Esto no reconocerá flotantes, enteros negativos o enteros en formato hexadecimal. Si no puede aceptar estas limitaciones, la respuesta de Slim a continuación será suficiente.
re
. Es una herramienta general y poderosa (para que aprendas algo muy útil). La velocidad es algo irrelevante en el análisis de registros (después de todo no es un solucionador numérico intensivo), el re
módulo está en la biblioteca estándar de Python y no hace daño cargarlo.
mumblejumble45mumblejumble
en las que sabía que solo había un número. La solución es simple int(filter(str.isdigit, your_string))
.
str
que luego anula el str
objeto y el método en Python base. Esa no es una buena práctica, ya que podría necesitarla más adelante en el script.
int(filter(...))
se elevará TypeError: int() argument must be a string...
para Python 3.5, por lo que puede usar la versión actualizada: int(''.join(filter(str.isdigit, your_string)))
para extraer todos los dígitos a un entero.
Yo usaría una expresión regular:
>>> import re
>>> re.findall(r'\d+', 'hello 42 I\'m a 32 string 30')
['42', '32', '30']
Esto también coincidiría con 42 de bla42bla
. Si solo desea números delimitados por límites de palabras (espacio, punto, coma), puede usar \ b:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')
['42', '32', '30']
Para terminar con una lista de números en lugar de una lista de cadenas:
>>> [int(s) for s in re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')]
[42, 32, 30]
int
sobre él y listo. +1 especialmente para la última parte. Sin r'\b\d+\b' == '\\b\\d+\\b'
embargo, sugeriría cadenas sin formato ( ).
int_list = [int(s) for s in re.findall('\\d+', 'hello 12 hi 89')]
map
.
Esto es más que un poco tarde, pero también puede extender la expresión regex para tener en cuenta la notación científica.
import re
# Format is [(<string>, <expected output>), ...]
ss = [("apple-12.34 ba33na fanc-14.23e-2yapple+45e5+67.56E+3",
['-12.34', '33', '-14.23e-2', '+45e5', '+67.56E+3']),
('hello X42 I\'m a Y-32.35 string Z30',
['42', '-32.35', '30']),
('he33llo 42 I\'m a 32 string -30',
['33', '42', '32', '-30']),
('h3110 23 cat 444.4 rabbit 11 2 dog',
['3110', '23', '444.4', '11', '2']),
('hello 12 hi 89',
['12', '89']),
('4',
['4']),
('I like 74,600 commas not,500',
['74,600', '500']),
('I like bad math 1+2=.001',
['1', '+2', '.001'])]
for s, r in ss:
rr = re.findall("[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", s)
if rr == r:
print('GOOD')
else:
print('WRONG', rr, 'should be', r)
Da todo bien!
Además, puede ver la expresión regular incorporada de AWS Glue
s = "4"
no devuelve coincidencias. ¿Se puede editar para que también se encargue de esto?
[+-]?\d*[\.]?\d*(?:(?:[eE])[+-]?\d+)?
Este grupo da algunos falsos positivos ( +
es decir , a veces se captura solo), pero puede manejar más formas, como .001
, además, no combina números automáticamente (como en s=2+1
)
[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?
, tan tonto de mi parte ... ¿cómo podría no pensar en eso?
Supongo que quieres flotadores no solo enteros, así que haría algo como esto:
l = []
for t in s.split():
try:
l.append(float(t))
except ValueError:
pass
Tenga en cuenta que algunas de las otras soluciones publicadas aquí no funcionan con números negativos:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string -30')
['42', '32', '30']
>>> '-3'.isdigit()
False
float
a int
.
re.findall("[-\d]+", "1 -2")
continue
lugar de pass
en el bucle?
Si sabe que solo habrá un número en la cadena, es decir, 'hola 12 hola', puede intentar filtrar.
Por ejemplo:
In [1]: int(''.join(filter(str.isdigit, '200 grams')))
Out[1]: 200
In [2]: int(''.join(filter(str.isdigit, 'Counters: 55')))
Out[2]: 55
In [3]: int(''.join(filter(str.isdigit, 'more than 23 times')))
Out[3]: 23
Pero ten cuidado! :
In [4]: int(''.join(filter(str.isdigit, '200 grams 5')))
Out[4]: 2005
TypeError: int() argument must be a string, a bytes-like object or a number, not 'filter'
- fijándolo mediante el usoint("".join(filter(str.isdigit, '200 grams')))
# extract numbers from garbage string:
s = '12//n,_@#$%3.14kjlw0xdadfackvj1.6e-19&*ghn334'
newstr = ''.join((ch if ch in '0123456789.-e' else ' ') for ch in s)
listOfNumbers = [float(i) for i in newstr.split()]
print(listOfNumbers)
[12.0, 3.14, 0.0, 1.6e-19, 334.0]
Estaba buscando una solución para eliminar las máscaras de cadenas, específicamente de los números de teléfono brasileños, esta publicación no respondió pero me inspiró. Esta es mi solución:
>>> phone_number = '+55(11)8715-9877'
>>> ''.join([n for n in phone_number if n.isdigit()])
'551187159877'
Usar Regex a continuación es la forma
lines = "hello 12 hi 89"
import re
output = []
#repl_str = re.compile('\d+.?\d*')
repl_str = re.compile('^\d+$')
#t = r'\d+.?\d*'
line = lines.split()
for word in line:
match = re.search(repl_str, word)
if match:
output.append(float(match.group()))
print (output)
con findall
re.findall(r'\d+', "hello 12 hi 89")
['12', '89']
re.findall(r'\b\d+\b', "hello 12 hi 89 33F AC 777")
['12', '89', '777']
findall()
repl_str = re.compile('\d+.?\d*')
debería ser: repl_str = re.compile('\d+\.?\d*')
Para un ejemplo reproducible usando python3.7 re.search(re.compile(r'\d+.?\d*'), "42G").group()
'42G' re.search(re.compile(r'\d+\.?\d*'), "42G").group()
'42'
line2 = "hello 12 hi 89"
temp1 = re.findall(r'\d+', line2) # through regular expression
res2 = list(map(int, temp1))
print(res2)
Hola ,
Puede buscar todos los enteros en la cadena a través del dígito utilizando la expresión Findall.
En el segundo paso, cree una lista res2 y agregue los dígitos encontrados en la cadena a esta lista
espero que esto ayude
Saludos, Diwakar Sharma
Esta respuesta también contiene el caso cuando el número es flotante en la cadena
def get_first_nbr_from_str(input_str):
'''
:param input_str: strings that contains digit and words
:return: the number extracted from the input_str
demo:
'ab324.23.123xyz': 324.23
'.5abc44': 0.5
'''
if not input_str and not isinstance(input_str, str):
return 0
out_number = ''
for ele in input_str:
if (ele == '.' and '.' not in out_number) or ele.isdigit():
out_number += ele
elif out_number:
break
return float(out_number)
Me sorprende ver que nadie ha mencionado aún el uso de itertools.groupby
una alternativa para lograr esto.
Puede usar itertools.groupby()
junto con str.isdigit()
para extraer números de la cadena como:
from itertools import groupby
my_str = "hello 12 hi 89"
l = [int(''.join(i)) for is_digit, i in groupby(my_str, str.isdigit) if is_digit]
El valor retenido l
será:
[12, 89]
PD: Esto es solo con fines ilustrativos para mostrar que, como alternativa, también podríamos usar groupby
para lograr esto. Pero esta no es una solución recomendada. Si desea lograr esto, debe usar la respuesta aceptada de fmark basada en la comprensión de la lista con un str.isdigit
filtro.
Solo estoy agregando esta respuesta porque nadie agregó una usando el manejo de excepciones y porque esto también funciona para flotantes
a = []
line = "abcd 1234 efgh 56.78 ij"
for word in line.split():
try:
a.append(float(word))
except ValueError:
pass
print(a)
Salida:
[1234.0, 56.78]
Para atrapar diferentes patrones, es útil consultar con diferentes patrones.
'[\ d] + [., \ d] +'
'[\ d] * [.] [\ d] +'
'[\ d] +'
(Nota: Ponga patrones complejos primero; de lo contrario, los patrones simples devolverán fragmentos de la captura compleja en lugar de que la captura compleja devuelva la captura completa).
p = '[\d]+[.,\d]+|[\d]*[.][\d]+|[\d]+'
A continuación, confirmaremos que hay un patrón presente re.search()
y luego devolveremos una lista iterable de capturas. Finalmente, imprimiremos cada captura utilizando la notación de paréntesis para subseleccionar el valor de retorno del objeto coincidente del objeto coincidente.
s = 'he33llo 42 I\'m a 32 string 30 444.4 12,001'
if re.search(p, s) is not None:
for catch in re.finditer(p, s):
print(catch[0]) # catch is a match object
Devoluciones:
33
42
32
30
444.4
12,001
Como ninguno de estos se refería a números financieros del mundo real en documentos de Excel y Word que necesitaba encontrar, aquí está mi variación. Maneja ints, flotantes, números negativos, números de moneda (porque no responde en división), y tiene la opción de soltar la parte decimal y solo devolver ints, o devolver todo.
También maneja el sistema de números de Indian Laks donde las comas aparecen de manera irregular, no cada 3 números separados.
No maneja la notación científica o los números negativos entre paréntesis en los presupuestos, parecerán positivos.
Tampoco extrae fechas. Hay mejores formas de encontrar fechas en cadenas.
import re
def find_numbers(string, ints=True):
numexp = re.compile(r'[-]?\d[\d,]*[\.]?[\d{2}]*') #optional - in front
numbers = numexp.findall(string)
numbers = [x.replace(',','') for x in numbers]
if ints is True:
return [int(x.replace(',','').split('.')[0]) for x in numbers]
else:
return numbers
@jmnas, me gustó tu respuesta, pero no encontró flotadores. Estoy trabajando en un script para analizar el código que va a un molino CNC y necesitaba encontrar las dimensiones X e Y que pueden ser enteros o flotantes, por lo que adapté su código a lo siguiente. Esto encuentra int, float con valores positivos y negativos. Todavía no encuentra valores con formato hexadecimal, pero podría agregar "x" y "A" a través de "F" a la num_char
tupla y creo que analizaría cosas como '0x23AC'.
s = 'hello X42 I\'m a Y-32.35 string Z30'
xy = ("X", "Y")
num_char = (".", "+", "-")
l = []
tokens = s.split()
for token in tokens:
if token.startswith(xy):
num = ""
for char in token:
# print(char)
if char.isdigit() or (char in num_char):
num = num + char
try:
l.append(float(num))
except ValueError:
pass
print(l)
La mejor opción que encontré está debajo. Extraerá un número y puede eliminar cualquier tipo de carbón.
def extract_nbr(input_str):
if input_str is None or input_str == '':
return 0
out_number = ''
for ele in input_str:
if ele.isdigit():
out_number += ele
return float(out_number)
Para los números de teléfono, simplemente puede excluir todos los caracteres que no sean dígitos con \ D en regex:
import re
phone_number = '(619) 459-3635'
phone_number = re.sub(r"\D", "", phone_number)
print(phone_number)