Seite 1 von 1

Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Samstag 19. September 2015, 22:28
von pixewakb
Ich parse eine HTML-Seite mit Python und nutze hier das bs4-Modul sowie requests. Ich erhalte dann eine Liste mit Listen je Zeile. Ich bekomme etwas in der Form von
\t\t1.122.344,56\t\t
heraus und das leider haufenweise. Im Netz habe ich mir jetzt zusammengestückelt:

Code: Alles auswählen

m = re.search('\t\t(.+?)\t\t', text)
if m:
    found = m.group(1)
    print(float(found.replace(".","").replace(",",".")))
Ich muss also aus jeder Zelle die eigentlichen Zahl (ggf. auch anderes) extrahieren und dann noch einmal in eine Gleitkommazahl umwandeln.

Meine Frage ist: Ist das die "effizienteste" Herangehensweise oder gibt es eine bessere Alternative? Üblicherweise würde ich so etwas mit strip("\t") oder replace("\t", "") lösen, was ich aber für nicht sehr effizient erachte. Jemand eine Idee!?

Am Ende mache ich aus den Listen ein Wörterbuch. Ich werde einen Tag noch mal bei Bing oder Yahoo! googlen, ob ich das direkt aus bs4 machen kann, befürchte aber im Moment noch, dass ich selber diesen Zwischenschritt mit den Listen benötige, weil ich die Daten verändern muss (s. o.).

Re: Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Samstag 19. September 2015, 23:16
von BlackJack
@pixewakb: Ich sehe jetzt nicht wozu man hier den regulären Ausdruck braucht. Whitespace vor und nach einer Zahlendarstellung stören `float()` überhaupt nicht:

Code: Alles auswählen

In [1]: float('\t\t1122344.56\t\t')
Out[1]: 1122344.56

Re: Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Samstag 19. September 2015, 23:40
von pixewakb
Ich bin beeindruckt. Darauf wäre ich schlicht nicht gekommen!

Ich muss dann aber immer noch den Tausenderpunkt rausnehmen und das Komma durch Punkt ersetzen. Mache ich das mit zweifachem replace() oder kann ich das irgendwie effizienter machen? Ich frage hier wegen der Kleinigkeit mal nach, weil das häufiger zum Einsatz kommt und sich in der Summe dann doch spürbar auswirken dürfte.

Re: Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Sonntag 20. September 2015, 00:24
von BlackJack
@pixewakb: Ich würde ja sagen darüber sollte man sich Gedanken machen wenn man nachgemessen hat und Beweise hat das ein signifikanter Teil der Laufzeit genau darauf aufgewendet wird. Dann könntest Du Dir die `translate()`-Methode anschauen.

Re: Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Sonntag 20. September 2015, 12:54
von pixewakb
string.translate() wird in Python 2.7 unter "Deprecated string functions" geführt und ist ab Python 3 anscheinend nicht mehr verfügbar, ich konnte es in der Dokumentation nicht mehr finden. Das ist kein Beinbruch!

Wenn - so habe ich es bislang verstanden - replace() OK ist, dann nutze ich es gerne auch. Ich habe den Quellcode im konkreten Fall aufgeräumt und urllib.request durch requests ersetzt und das Daten herauslösen jetzt mit bs4 erledigt. Die Frage hier ergab sich aus diesem Zusammenhang.

Ich habe da noch einigen anderen Quellcode wo ich schneller Ergebnisse erzielen kann, d. h. da dürfte Refactoring schneller zu mehr Geschwindigkeit führen.

Vielen Dank!

Re: Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Sonntag 20. September 2015, 13:02
von BlackJack
@pixewakb: `string.translate()` ist eine *Funktion* die man tatsächlich schon länger nicht mehr verwenden sollte, eben weil die Funktionalität schon länger als `translate()`-*Methode* auf Zeichenketten existiert.

Re: Effizientes Herauslösen von Zahlen aus einem String

Verfasst: Sonntag 20. September 2015, 13:13
von pixewakb
OK, danke!

Ich habe es aus dem Netz zusammengestückelt, nur um es mal zu testen:

Code: Alles auswählen

# source: http://docs.python.org/library/timeit.html

def test_1():
    """Stupid test function"""
    text = '\n\t\t\t4.123,00\n\t\t'
    zahl = float(text.replace(".","").replace(",","."))
    # print(zahl)

def test_2():
    """Stupid test function"""
    text = '\n\t\t\t4.123,00\n\t\t'
    zahl = float(text.translate({ord('.'): '', ord(','): '.'}))
    # print(zahl)

if __name__ == '__main__':
    from timeit import Timer
    t1 = Timer("test_1()", "from __main__ import test_1")
    t2 = Timer("test_2()", "from __main__ import test_2")
    print("1:", t1.timeit())
    print("2:", t2.timeit())
Liefert dann:
1: 2.4271164235080303
2: 6.236407278201973

Ich bleibe beim replace(). DANKE!