Effizientes Herauslösen von Zahlen aus einem String

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

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.).
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
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

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.
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.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

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!
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.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

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!
Antworten