Ich würde alle in einer Zeichenfolge enthaltenen Zahlen extrahieren. Welches ist für den Zweck, reguläre Ausdrücke oder die Methode isdigit()
am besten geeignet?
Beispiel:
line = "hello 12 hi 89"
Ergebnis:
[12, 89]
Wenn Sie nur positive ganze Zahlen extrahieren möchten, versuchen Sie Folgendes:
>>> str = "h3110 23 cat 444.4 rabbit 11 2 dog"
>>> [int(s) for s in str.split() if s.isdigit()]
[23, 11, 2]
Ich würde argumentieren, dass dies aus drei Gründen besser ist als das Regex-Beispiel. Erstens benötigen Sie kein weiteres Modul. Zweitens ist es besser lesbar, da Sie die Regex-Minisprache nicht analysieren müssen. und drittens ist es schneller (und damit wahrscheinlich pythonischer):
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
Dies erkennt keine Gleitkommazahlen, negativen Ganzzahlen oder Ganzzahlen im Hexadezimalformat. Wenn Sie diese Einschränkungen nicht akzeptieren können, erledigt Antwort von slim unten den Trick.
Ich würde einen regulären Ausdruck verwenden:
>>> import re
>>> re.findall(r'\d+', 'hello 42 I\'m a 32 string 30')
['42', '32', '30']
Dies würde auch 42 von bla42bla
entsprechen. Wenn Sie nur durch Wortgrenzen (Leerzeichen, Punkt, Komma) begrenzte Zahlen möchten, können Sie\b verwenden:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')
['42', '32', '30']
So erhalten Sie eine Liste mit Zahlen anstelle einer Liste mit Zeichenfolgen:
>>> [int(s) for s in re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string 30')]
[42, 32, 30]
Dies ist mehr als ein bisschen spät, aber Sie können den regulären Ausdruck erweitern, um auch die wissenschaftliche Notation zu berücksichtigen.
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)
Gibt alles gut!
Zusätzlich können Sie sich den AWS Glue-Regex ansehen
Ich gehe davon aus, dass Sie nicht nur ganze Zahlen, sondern auch Gleitkommazahlen verwenden möchten.
l = []
for t in s.split():
try:
l.append(float(t))
except ValueError:
pass
Beachten Sie, dass einige der anderen hier aufgeführten Lösungen nicht mit negativen Zahlen funktionieren:
>>> re.findall(r'\b\d+\b', 'he33llo 42 I\'m a 32 string -30')
['42', '32', '30']
>>> '-3'.isdigit()
False
Wenn Sie wissen, dass die Zeichenfolge nur eine einzige Zahl enthält, z.
Zum Beispiel:
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
Aber sei vorsichtig !!! :
In [4]: int(''.join(filter(str.isdigit, '200 grams 5')))
Out[4]: 2005
# extract numbers from garbage string:
s = '12//n,[email protected]#$%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]
Ich suchte nach einer Lösung, um die Masken von Zeichenfolgen zu entfernen, insbesondere von brasilianischen Telefonnummern. Dieser Beitrag hat mich nicht beantwortet, aber inspiriert. Das ist meine Lösung:
>>> phone_number = '+55(11)8715-9877'
>>> ''.join([n for n in phone_number if n.isdigit()])
'551187159877'
Diese Antwort enthält auch den Fall, dass die Zahl in der Zeichenfolge steht
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)
Mit Regex unten ist der Weg
lines = "hello 12 hi 89"
import re
output = []
line = lines.split()
for Word in line:
match = re.search(r'\d+.?\d*', Word)
if match:
output.append(float(match.group()))
print (output)
Ich bin erstaunt zu sehen, dass noch niemand die Verwendung von itertools.groupby
als Alternative erwähnt hat, um dies zu erreichen .
Sie können itertools.groupby()
zusammen mit str.isdigit()
verwenden, um Zahlen aus einer Zeichenfolge zu extrahieren als:
_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]
_
Der von l
gehaltene Wert ist:
_[12, 89]
_
PS: Dies ist nur zur Veranschaulichung gedacht, um dies als Alternativ könnten wir auch groupby
verwenden, um dies zu erreichen. Dies ist jedoch keine empfohlene Lösung. Wenn Sie dies erreichen möchten, sollten Sie akzeptierte Antwort von fmark verwenden, basierend auf der Verwendung des Listenverständnisses mit _str.isdigit
_ als Filter.
Ich füge diese Antwort nur hinzu, weil niemand sie mit der Ausnahmebehandlung hinzugefügt hat und weil dies auch für Floats funktioniert
a = []
line = "abcd 1234 efgh 56.78 ij"
for Word in line.split():
try:
a.append(float(Word))
except ValueError:
pass
print(a)
Ausgabe :
[1234.0, 56.78]
Da sich keines dieser Dokumente mit realen Finanzzahlen in Excel- und Word-Dokumenten befasste, die ich finden musste, ist hier meine Variante. Es verarbeitet Ints, Floats, negative Zahlen und Währungszahlen (da es beim Teilen nicht antwortet) und hat die Option, den Dezimalteil zu löschen und einfach Ints oder alles zurückzugeben.
Es behandelt auch Indian Laks Zahlensystem, bei dem Kommas unregelmäßig erscheinen, nicht alle 3 Zahlen auseinander.
Es behandelt keine wissenschaftliche Notation oder negative Zahlen in Klammern im Budget - wird positiv erscheinen.
Es werden auch keine Daten extrahiert. Es gibt bessere Möglichkeiten, Daten in Zeichenfolgen zu finden.
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, mir hat deine Antwort gefallen, aber es wurden keine Schwimmer gefunden. Ich arbeite an einem Skript zum Parsen von Code in einer CNC-Fräse und musste sowohl X- als auch Y-Dimensionen finden, die Ganzzahlen oder Gleitkommazahlen sein können. Daher habe ich Ihren Code an die folgenden Punkte angepasst. Dies findet int, float mit positiven und negativen Werten. Findet immer noch keine hexadezimal formatierten Werte, aber Sie könnten "x" und "A" bis "F" zum Tupel num_char
hinzufügen, und ich denke, es würde Dinge wie "0x23AC" analysieren.
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)
Die beste Option, die ich gefunden habe, ist unten. Es extrahiert eine Zahl und kann jede Art von Zeichen eliminieren.
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)