it-swarm.com.de

Wie extrahiere ich Zahlen aus einem String in Python?

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]
365
pablouche

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.

412
fmark

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]
382
Vincent Savard

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
64
jmnas

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
53
dfostic
# 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]
12
AndreiS

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'
9
Sidon

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)
7
Menglong Li

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)
6
sim

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.

5

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]
2
Raghav

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
2
Marc Maxmeister

@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)
1
ZacSketches

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)    
0
Ajay Kumar