web-dev-qa-db-de.com

So extrahieren Sie eine gleitende Zahl aus einer Zeichenfolge

Ich habe eine Reihe von Zeichenfolgen ähnlich Current Level: 13.4 db. und ich möchte nur die Gleitkommazahl extrahieren. Ich sage schwebend und nicht dezimal, da es manchmal ganz ist. Kann RegEx dies tun oder gibt es einen besseren Weg?

84
Flowpoke

Wenn Ihr Float immer in Dezimalschreibweise ausgedrückt wird, ist das ungefähr so

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

kann ausreichen.

Eine robustere Version wäre:

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

Wenn Sie eine Benutzereingabe validieren möchten, können Sie alternativ auch direkt darauf zugreifen, um nach einem Float zu suchen:

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
165
miku

Möglicherweise möchten Sie etwas Ähnliches ausprobieren, das alle Grundlagen abdeckt, einschließlich des Verzichts auf Leerzeichen nach der Nummer:

>>> 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']
>>>

Zum einfachen Kopieren und Einfügen:

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")
54
John Machin

Python docs hat eine Antwort, die +/- und Exponentennotation abdeckt

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

Dieser reguläre Ausdruck unterstützt keine internationalen Formate, bei denen ein Komma als Trennzeichen zwischen dem ganzen und dem gebrochenen Teil verwendet wird (3,14159). In diesem Fall ersetzen Sie alle \. mit [.,] im obigen Float-Regex.

                        Regular Expression
International float     [-+]?(\d+([.,]\d*)?|[.,]\d+)([eE][-+]?\d+)?
22
IceArdor
re.findall(r"[-+]?\d*\.\d+|\d+", "Current Level: -13.2 db or 14.2 or 3")

wie oben beschrieben, funktioniert wirklich gut! Ein Vorschlag jedoch:

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

gibt auch negative int Werte zurück (wie -3 am Ende dieser Zeichenkette)

6
Martin

Sie können den folgenden regulären Ausdruck verwenden, um Ganzzahl- und Gleitkommawerte aus einer Zeichenfolge abzurufen:

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

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

Danke Rex

4
user3613331

Ich denke, dass Sie interessante Dinge in der folgenden Antwort von mir finden werden, die ich für eine vorhergehende ähnliche Frage gemacht habe:

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

In dieser Antwort habe ich ein Muster vorgeschlagen, mit dem ein Regex jede Art von Zahl erfassen kann, und da ich nichts anderes hinzuzufügen habe, denke ich, dass es ziemlich vollständig ist

2
eyquem

Ein weiterer Ansatz, der besser lesbar sein kann, ist die einfache Typkonvertierung. Ich habe eine Ersatzfunktion hinzugefügt, um Fälle abzudecken, in denen Personen europäische Dezimalstellen eingeben können:

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

Dies hat jedoch auch Nachteile. Wenn jemand "1,000" eingibt, wird dies in 1 konvertiert. Außerdem wird davon ausgegangen, dass die Leute Leerzeichen zwischen den Wörtern eingeben. Dies ist bei anderen Sprachen wie Chinesisch nicht der Fall.

0
Tim McNamara