re.findall gibt zu viele Werte aus

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
cobraKhan
User
Beiträge: 3
Registriert: Donnerstag 24. November 2016, 08:59

Hallo zusammen,

ich arbeite gerade 'Automate the Boring Stuff with Python' durch und konnte bisher jedes Problem mehr oder minder selbsständig lösen. Dazu sei gesagt, dass ich nicht über mehr als das Schulbasiswissen aus dem Informatikunterricht verfüge und daher die nun folgende Frage möglicherweise lapidar erscheinen mag.

Mir bereitet gerade die Funktion re.findall etwas Kopfzerbrechen. Ich habe ein Regex erstellt, dass deutsche Telefonnummern erkennen soll. Mittels re.search funktioniert das auch wunderbar. Wende ich jedoch folgenden Code an

Code: Alles auswählen

import re

phoneNumRegex = re.compile(r'(0(\d){2}(\d)*)-((\d){3}(\d)*)'

print(phoneNumRegex.findall('Privat: 05381-6370484 Geschäftlich 0157-24481634')

So bekomme ich folgendes Tuple ausgegeben:
(Edit): Jetzt passt auch die Ausgabe. Habe mit verschiedenen Nummern experimentiert und leider die Falsche Ausgabe gepostet.

Code: Alles auswählen

[('05381', '3', '1', '6370484', '7', '4'), ('0157', '5', '7', '24481634', '4', '4')]
Meine Frage ist jetzt, weshalb die Ziffern 3, 1, 7, 4 und 5 jeweils einzeln ausgegeben werden. Mir scheint als wenn für (\d)* jeweils die zuletzt gefundene Ziffer ausgegeben wird. Für mich sind dieses Werte jedoch überflüssig. Wie kann ich dies verhindern? Oder ist das so beabsichtigt?

P.S.: Ich hab schon die Suche bemüht. Gefunden habe ich schließlich nichts, was aber auch damit zusammenhängen mag, dass ich nicht wirklich weiß, wie ich meine Suchanfrage treffend formulieren sollte.

(Edit): Danke für das Ändern der Codeboxen.

Vielen Dank und viele Grüße
Zuletzt geändert von Anonymous am Donnerstag 24. November 2016, 09:20, insgesamt 2-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@cobraKhan: Das Ergebnis enthält ein Tupel mit einem Element für jede Gruppe im Muster.

Warum hättest Du das so nicht erwartet? Also wonach hättest Du denn erwartet das entschieden wird ob eine Gruppe zu einem Wert führt oder eben nicht?

Wobei die inneren Gruppen auch nicht wirklich Sinn machen, insbesondere wenn man gar nicht separat an ihrem Inhalt interessiert ist.

Wenn sie Sinn machen würden und man keinen Wert dafür im Ergebnis haben möchte, kann man eine „non-capturing“ Gruppe verwenden. Siehe Dokumentation zum `re`-Modul.

Ungetestet: r'(0\d{2,})-(\d{3,})'

`phoneNumRegex` hält sich von der Schreibweise übrigens nicht an den Style Guide for Python Code.
cobraKhan
User
Beiträge: 3
Registriert: Donnerstag 24. November 2016, 08:59

Hi,

jetzt, wo Du es sagst, fällt es mir wie Schuppen von den Augen. (\3)* ist ja in der Tat überflüssig. Dank Deines Hinweises erhalte ich jetzt immerhin

Code: Alles auswählen

[('05381', '1', '6370484', '4'), ('0157', '7', '24481634', '4')]
.

Mir ist trotzdem nicht ganz klar, wieso die Einzelziffern jeweils eine eigene Gruppe darstellen. Ich dachte (0\d){2,}) und (\d){3,}) würden jeweils eine Gruppe für sich darstellen.

Was den Verstoß gegen den Style Guide anbelangt: ich bitte dies zu entschuldigen. Beschäftige mich erst kurzzeitig mit Python und der Autor des genannten Buches erwähnt zwar, dass er dies so für den Einstieg einfacher hält. Klärt aber meiner Erinnerung nach nicht über die korrekte Formatierung auf.

Vielen Dank für die rasche Hilfe!
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

Deine Lösung war ja richtig, nur umständlich und zu viele Klammern.
Jede Klammer erzeugt eine Gruppe.

Code: Alles auswählen

phoneNumRegex = re.compile(r'(0\d{2}\d*)-(\d{3}\d*)'
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@cobraKhan: jetzt hast Du ja immer noch zu viele Klammern. Jeder Klammerausdruck führt zu einer Gruppe. Wird eine Gruppe per * mehrfach angewendet, so wird nur das letzte Vorkommen dieser Gruppe zurückgegeben. Deine Gruppen heißen halt "Vorwahl", und innerhalb der Gruppe "Vorwahl" gibt es noch eine Gruppe "Ziffer", die beim letzten Match die letzte Ziffer enthält.

@heiner88: wenn das Ergebnis nicht das gewünschte ist, kann es ja keine richtige Lösung sein. Und 2 oder mehr Vorkommen schreibt man nicht als "\d{2}\d*" sondern als "\d{2,}".
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

@sirius: Das weiß ich auch. Ich bleibe aber lieber so nah wie möglich an der Originalfrage. Optimieren kann der Fragesteller selber, wenn er seine eigene Lösung verstanden hat.
cobraKhan
User
Beiträge: 3
Registriert: Donnerstag 24. November 2016, 08:59

Ah, jetzt verstehe ich es. Mein Fehler lag darin, dass ich davon ausgegangen bin, dass die geschweiften Klammern oder eben das Asterix einen Wert in einfachen Klammern voraussetzt.

Geht aus dem Buch leider nicht in dieser Deutlichkeit hervor, dass dem nicht so ist.

Vielen Dank für die sehr erhellenden Kommentare!
Antworten