Risposte:
Se desideri estrarre solo numeri interi positivi, prova quanto segue:
>>> str = "h3110 23 cat 444.4 rabbit 11 2 dog"
>>> [int(s) for s in str.split() if s.isdigit()]
[23, 11, 2]
Direi che questo è meglio dell'esempio regex per tre ragioni. Innanzitutto, non è necessario un altro modulo; secondo, è più leggibile perché non è necessario analizzare il mini-linguaggio regex; e terzo, è più veloce (e quindi probabilmente più pitonico):
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
Ciò non riconoscerà float, numeri interi negativi o numeri interi in formato esadecimale. Se non riesci ad accettare queste limitazioni, la risposta di slim qui sotto farà il trucco.
re
. È uno strumento generale e potente (quindi impari qualcosa di molto utile). La velocità è in qualche modo irrilevante nell'analisi dei log (non è un risolutore numerico intenso dopo tutto), il re
modulo si trova nella libreria Python standard e non fa male caricarlo.
mumblejumble45mumblejumble
in cui sapevo che c'era un solo numero. La soluzione è semplicemente int(filter(str.isdigit, your_string))
.
str
che quindi sovrascrive l' str
oggetto e il metodo in Python di base. Non è una buona pratica poiché potresti averne bisogno più avanti nella sceneggiatura.
int(filter(...))
rilancierà TypeError: int() argument must be a string...
per Python 3.5, quindi puoi usare la versione aggiornata: int(''.join(filter(str.isdigit, your_string)))
per estrarre tutte le cifre in un intero.
Vorrei usare un regexp:
>>> import re
>>> re.findall(r'\d+', 'hello 42 I\'m a 32 string 30')
['42', '32', '30']
Ciò corrisponderebbe anche a 42 da bla42bla
. Se vuoi solo numeri delimitati da limiti di parole (spazio, punto, virgola), puoi usare \ b:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')
['42', '32', '30']
Per finire con un elenco di numeri anziché un elenco di stringhe:
>>> [int(s) for s in re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')]
[42, 32, 30]
int
su di esso e il gioco è fatto. +1 soprattutto per l'ultima parte. Suggerirei stringhe grezze ( r'\b\d+\b' == '\\b\\d+\\b'
) però.
int_list = [int(s) for s in re.findall('\\d+', 'hello 12 hi 89')]
map
.
Questo è più che un po 'in ritardo, ma puoi estendere l'espressione regex per tenere conto anche della notazione scientifica.
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)
Dà tutto bene!
Inoltre, puoi guardare la regex integrata di AWS Glue
s = "4"
Non restituisce corrispondenze. Può essere modificato per occuparsi anche di questo?
[+-]?\d*[\.]?\d*(?:(?:[eE])[+-]?\d+)?
Questo gruppo fornisce alcuni falsi positivi (cioè +
viene catturato da solo a volte), ma è in grado di gestire più forme, come .001
, inoltre, non combina automaticamente i numeri (come in s=2+1
)
[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?
- così sciocco da parte mia ... come potrei non pensarci?
Suppongo che tu voglia float non solo numeri interi, quindi farei qualcosa del genere:
l = []
for t in s.split():
try:
l.append(float(t))
except ValueError:
pass
Nota che alcune delle altre soluzioni pubblicate qui non funzionano con numeri negativi:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string -30')
['42', '32', '30']
>>> '-3'.isdigit()
False
float
passa a int
.
re.findall("[-\d]+", "1 -2")
continue
invece che pass
nel ciclo?
Se sai che nella stringa sarà presente un solo numero, ad esempio "ciao 12 ciao", puoi provare a filtrare.
Per esempio:
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
Ma stai attento !!! :
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'
- risolto usandoint("".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]
Stavo cercando una soluzione per rimuovere le maschere delle stringhe, in particolare dai numeri di telefoni brasiliani, questo post non ha risposto ma mi ha ispirato. Questa è la mia soluzione:
>>> phone_number = '+55(11)8715-9877'
>>> ''.join([n for n in phone_number if n.isdigit()])
'551187159877'
Utilizzando Regex di seguito è il modo
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*')
dovrebbe essere: repl_str = re.compile('\d+\.?\d*')
Per un esempio riproducibile 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)
Ciao ,
puoi cercare tutti i numeri interi nella stringa tramite cifra usando l'espressione findall.
Nel secondo passaggio creare un elenco res2 e aggiungere le cifre trovate nella stringa a questo elenco
spero che sia di aiuto
Saluti, Diwakar Sharma
Questa risposta contiene anche il caso in cui il numero è mobile nella stringa
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)
Sono sorpreso di vedere che nessuno ha ancora menzionato l'uso di itertools.groupby
un'alternativa per raggiungere questo obiettivo.
È possibile utilizzare itertools.groupby()
insieme str.isdigit()
per estrarre i numeri dalla stringa come:
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]
Il valore trattenuto l
sarà:
[12, 89]
PS: Questo è solo a scopo illustrativo per mostrare che come alternativa potremmo anche usare groupby
per raggiungere questo obiettivo. Ma questa non è una soluzione raccomandata. Se vuoi raggiungere questo obiettivo, dovresti utilizzare la risposta accettata di fmark in base all'uso della comprensione dell'elenco con str.isdigit
come filtro.
Sto solo aggiungendo questa risposta perché nessuno ha aggiunto nessuno usando la gestione delle eccezioni e perché questo funziona anche per i float
a = []
line = "abcd 1234 efgh 56.78 ij"
for word in line.split():
try:
a.append(float(word))
except ValueError:
pass
print(a)
Produzione :
[1234.0, 56.78]
Per acquisire modelli diversi è utile eseguire query con modelli diversi.
'[\ D] + [., \ D] +'
'[\ D] * [.] [\ D] +'
'[\ D] +'
(Nota: metti prima i modelli complessi altrimenti i modelli semplici restituiranno blocchi della cattura complessa anziché la cattura complessa che restituisce la cattura completa).
p = '[\d]+[.,\d]+|[\d]*[.][\d]+|[\d]+'
Di seguito, confermeremo che è presente un modello re.search()
, quindi restituiamo un elenco iterabile di catture. Infine, stamperemo ogni cattura usando la notazione parentesi per selezionare il valore restituito dell'oggetto match dall'oggetto match.
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
Ritorna:
33
42
32
30
444.4
12,001
Dal momento che nessuno di questi si occupava di numeri finanziari del mondo reale in documenti di Excel e word che dovevo trovare, ecco la mia variazione. Gestisce ints, float, numeri negativi, numeri di valuta (perché non risponde alla divisione) e ha la possibilità di eliminare la parte decimale e restituire solo ints o restituire tutto.
Gestisce anche il sistema di numeri dei Laks indiani in cui le virgole appaiono in modo irregolare, non ogni 3 numeri a parte.
Non gestisce la notazione scientifica o i numeri negativi inseriti tra parentesi nei budget - sembreranno positivi.
Inoltre non estrae le date. Esistono modi migliori per trovare le date nelle stringhe.
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, mi è piaciuta la tua risposta, ma non ha trovato float. Sto lavorando a uno script per analizzare il codice che va in un mulino a controllo numerico e dovevo trovare le dimensioni X e Y che possono essere numeri interi o float, quindi ho adattato il tuo codice al seguente. Questo trova int, float con val positivi e negativi. Non trova ancora valori in formato esadecimale ma potresti aggiungere "x" e "A" a "F" alla num_char
tupla e penso che analizzerebbe cose come '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)
L'opzione migliore che ho trovato è di seguito. Estrarrà un numero e può eliminare qualsiasi tipo di carattere.
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)
Per i numeri di telefono puoi semplicemente escludere tutti i caratteri non digitati con \ D in regex:
import re
phone_number = '(619) 459-3635'
phone_number = re.sub(r"\D", "", phone_number)
print(phone_number)