Seite 1 von 1
Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 15:41
von kruphi
Hallo,
ich bin neu in dieser Sprache, ich hoffe ihr könnt mir da evtl. helfen.
Ich schreibe gerade ein Programm das mir XML Daten für ein anderes Programm aufbereitet.
Mein Problem, die Strassen stehen in dem XML in einem Knoten.
"Hauptstraße 80"
"Am Schlosswall 13"
" vor dem Brunnen 9b"
Ich müsste die Hausnummern von Straßennamen trennen. Hier im Forum habe ich einige Ansätze mit split gefunden.
Leider ohne großen Erfolg.
Als Erklärung. So sieht meine Lösung vereinfacht aus.
Code:
Code: Alles auswählen
for i in all:
a=all[i].strasse.encode("utf-8")
for i in list(a):
try:
if isinstance( int(i), int ):
print i,
Vielen Dank schon mal für eure Hilfe!
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 16:25
von cofi
Willkommen im Forum und so wie es aussieht auch zu Python!
Zu deiner Loesung .. die ist einfach kaputt.
Zuerst solltest du deine XML-Dateien mit einem XML-Parser oeffnen, die sollten dir schon _dekodierte_ Strings zurueckgeben. Wenn du etwas _kodierst_, kommt eine Bytesequenz heraus. Sowas willst du ausserhalb von Input und Output nicht haben.
Das `list(a)` ist ueberfluessig, du erstellst hier eine Liste von Bytes aus einer Bytesequenz .. zum iterieren macht das keinen Unterschied.
`isinstance(int(i), int)` ist immer wahr ... oder wirft einen `ValueError` weil `i` keine Zahl ist oder als (Dezimal-)Zahl gelesen werden kann, insofern kannst du auch direkt `int(i)` nehmen.
Hier ein simpler Ansatz, von dem ich allerdings nicht weiss ob er korrekt ist - dafuer habe ich zu wenig wissen ueber Hausnummern:
Code: Alles auswählen
In [1]: streets = ["Hauptstraße 80",
...: "Am Schlosswall 13",
...: " vor dem Brunnen 9b"]
In [2]:
In [2]: for street in streets:
...: street, number = street.rsplit(' ', 1)
...: print street
...: print number
...:
Hauptstraße
80
Am Schlosswall
13
vor dem Brunnen
9b
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 16:34
von EyDu
Und
hier noch ein paar Hinweise zu Straßennamen und Hausnummern.
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 17:00
von kruphi
Erstmal riesen Dank für deine Antwort. Das hat mir auf jeden Fall schon einmal einen guten Tip gegeben.
Habe gerade einmal schnell versucht dies umzusetzen, leider nur mit einem Teil erfolg.
Die Daten habe ich schon aus der XML in ein dictionary geprasst.
Jetzt will ich nur noch Hausnummern von Strassen trennen. Dazu habe ich mir( an dieser Stelle noch einmal ein großes Danke schön) teile von deinem Code geklaut

.
Code: Alles auswählen
def getHausNr(a):
street, number = a.rsplit(' ', 1)
return number
jetzt will ich in meinem Hauptprogramm diese Funktion aufrufen:
da bekomme ich folgenden Fehler:
ValueError: need more than 1 value to unpack
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 18:01
von cofi
Nun, deine Daten sehen wohl anders aus als du denkst:
Code: Alles auswählen
In [1]: street, number = 'Strasse1'.rsplit(' ', 1)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-1-0806250e223f> in <module>()
----> 1 street, number = 'Strasse1'.rsplit(' ', 1)
ValueError: need more than 1 value to unpack
Und gib in Zukunft bitte den _ganzen_ Traceback an, statt nur der Fehlermeldung.
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 18:36
von snafu
EyDu hat geschrieben:Und
hier noch ein paar Hinweise zu Straßennamen und Hausnummern.
Wobei es in dem von dir verlinkten Thread ja hauptsächlich darum geht, schlecht formatierte Adresseingaben wieder gerade zu bügeln. Sowas ist schon fast unlösbar, wenn man wirklich jeden erdenklichen Fall korrekt behandeln möchte.
Aber hier ist es ja so, dass die Daten offenbar sauber eingegeben wurden. Wenn also garantiert ist, dass nach dem am weitesten rechts stehenden Leerraum auf jeden Fall die Hausnummer kommt und dass ein ggf folgender Buchstabe direkt an der Hausnummer hängt, dann ist `.rsplit(' ', 1)` IMHO schon sehr robust. Fies wird es natürlich, wenn bei der Hausnummer noch sowas wie "Zimmer 3" oder so steht.
Jedenfalls ist es bei den vorgenannten einfachen Fällen von Hausnummer-Angaben doch an sich ziemlich egal, wie der zugehörige Straßenname aussieht. Man splittet halt einfach am letzten Leerzeichen und ist glücklich. Oder wolltest du auf etwas anderes hinaus?
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 18:43
von snafu
@kruphi: Versuch mal folgendes, damit man in der Schleife besser sieht, bei welchem String es kracht:
Code: Alles auswählen
def getHausNr(a):
try:
street, number = a.rsplit(' ', 1)
except ValueError:
print 'Fehler bei:', a
raise
return number
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 19:51
von BlackJack
@snafu: 'Strasse 105' kann ein gültiger *Strassenname* sein. Ohne Hausnummer.
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 25. Juli 2013, 23:50
von Sirius3
@kruphi: Du solltest noch an Deinen Variablennamen arbeiten. »all« ist eine builtin Funktion und sollte nicht als Variablenname verwendet werden. »i« läßt auf eine Zahl schließen und nicht auf einen Dictionary-Key.
Re: Hausnummern und Straßen trennen
Verfasst: Freitag 26. Juli 2013, 07:13
von snafu
BlackJack hat geschrieben:@snafu: 'Strasse 105' kann ein gültiger *Strassenname* sein. Ohne Hausnummer.
Wie bereits geschrieben: Es kommt darauf an, welche Garantien für die Datenlage gegeben werden. Was soll man denn aus solchen Einwänden schließen? Dass eine automatisierte Auswertung gar nicht erst begonnen werden soll, weil einer von 10.000 Fällen durch's Raster fallen könnte...?
Es gibt halt Fälle - wie den von dir gezeigten -, die man ganz einfach nicht (erfolgreich) automatisiert behandeln kann. Da muss man dann ggf die Ergebnisse noch durch eine Adresssuche jagen und die fehlerhaften Daten per Hand korrigieren. Das einzige, was dies zeigt, ist dass man sich in solchen Fällen nicht bloß auf die Ergebnisse eines eher naiven Ansatzes verlassen kann. Trotzdem spart es ja schon jede Menge Arbeit, zunächst so vorzugehen.
Re: Hausnummern und Straßen trennen
Verfasst: Freitag 26. Juli 2013, 10:40
von lunar
@snafu Vielleicht eher, dass man den Nutzer die Adresse direkt richtig eingeben lässt, oder besser gar nicht erst nach Straße und Hausnummer trennt, wenn es nicht zwingend notwendig ist. Je nach Einzugsbereich der Anwendung gerät man sonst nämlich schnell in Teufels Küche, denn es gibt auch Adresse ohne numerische Hausnummer, oder gar ganz ohne Hausnummer.
Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 13:49
von kruphi
Vielen Dank an dieser Stelle für eure Tips/Lösungen!
Diese haben mir sehr geholfen und ich konnte das Problem lösen.
Um die Lösung für andere evtl. zu vervollständigen beschreibe ich das gerade ein schnell hier.
Mit den Lösungsvorschlag von snafu
Code: Alles auswählen
def getHausNr(a):
try:
street, number = a.rsplit(' ', 1)
except ValueError:
print 'Fehler bei:', a
raise
return number
konnte ich erkennen bei welchem Datensatz der Fehler passierte. Draus ließ sich erkennen, einige der Straßen waren Fehlerhaft eingegeben und erzeugten so den Fehler.
Ich habe
(natürlich mit eurer Hilfe) das Problem wie folgt gelöst!
Code: Alles auswählen
def getHausNr(a):
try:
street, number = a.rsplit(' ', 1)
return number
except ValueError:
print 'Fehler bei:', a
log.fehler("Strassennummer auslesen ", " Kein Strassennummer vorhanden")
return 0
Ich wollte mich an dieser Stelle nur noch einmal bedanken!
Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 14:49
von BlackJack
@kruphi: Strassennummer und Hausnummer sind IMHO nicht synonym. Du solltest Dich da vielleicht auf die Bezeichnung Hausnummer beschränken.
Bei fehlender Hausnummer würde ich eher die leere Zeichenkette statt 0 verwenden, denn sonst würde die Funktion je nach Argument eine Zeichenkette oder eine Zahl zurückgeben.
Code: Alles auswählen
def get_house_number(street):
_street_name, _, number = street.rpartition(' ')
if not number:
LOG.error(
'Strassennummer auslesen, keine Strassennummer vorhanden: %s',
street
)
return number
`LOG` ist in diesem Fall ein `Logger` aus dem `logging`-Modul. Man muss das Rad ja nicht neu erfinden.
Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 15:09
von kruphi
@BlackJack
die log Geschichten habe ich mir damals als Übung selbst zusammen geschrieben.
Als Lernender muss man das Rad evtl. einfach mal neu erfinden um zu entdecken bzw. kennen zu lernen!
Oder sollte ich solche Dinge lieber durch bekannte Module ersetzten? Ich dachte mir, es frisst so ja kein Brot.......also lasse ich es ??
Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 16:05
von snafu
Ich würde beim produktiven Einsatz wohl eher einen Integer anstatt einer Zeichenkette zurückliefern. Wenn keine Hausnummer ermittelt werden konnte, stellt dies - je nach Sichtweise - nicht zwangsläufig einen Fehler dar. Deshalb würde meine Variante in dem Fall einfach `None` zurückliefern, denn die Hausnummer 0 könnte es ja theoretisch trotzdem geben. `None` hat außerdem den Vorteil, dass es recht schnell kracht, wenn jemand die Rückgabe nicht überprüft. Meistens bevorzugt man ja eine Exception anstatt den Anwender zur Prüfung des Rückgabewertes zu nötigen, aber ich denke, in diesem Fall ist `None` schon okay.
Unter Verwendung des `logging`-Moduls könnte eine mögliche Herangehensweise dann so aussehen:
Code: Alles auswählen
#!/usr/bin/env python
import logging
def get_house_number(address):
try:
street, number = address.strip().rsplit(' ', 1)
return int(number)
except ValueError:
return None
def get_house_numbers(addresses, logger=None):
result = []
for address in addresses:
house_number = get_house_number(address)
if house_number is None and logger is not None:
msg = 'Failed to determine house number: {!r}'
logger.warning(msg.format(address))
result.append(house_number)
return result
def main():
logging_format = '%(levelname)s: %(message)s'
logging.basicConfig(filename='errors.log', format=logging_format)
with open('addresses.txt') as addressfile:
house_numbers = get_house_numbers(addressfile, logging.getLogger())
print house_numbers
if __name__ == '__main__':
main()
Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 16:08
von BlackJack
@kruphi: Zum lernen kann man Räder natürlich neu erfinden, aber ich hatte den Eindruck hier ging es eher darum tatsächlich zu loggen. Und da würde ich was vorhandenes nehmen, wenn es denn schon von der Standardbibliothek angeboten wird.
Logging braucht man ja öfter mal, und dann müsste man das ja entweder jedes mal neu schreiben, oder selber so etwas wie ein `logging`-Modul ausgliedern und pflegen.
@snafu: Wie stellst Du die Hausnummern '42a' oder '23-24' oder '4711 A-E' als ganze Zahlen dar?

Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 16:33
von snafu
Stimmt, das mit dem Integer war ein Schnellschuss. Es muss zwangsläufig bei einem String bleiben.
Bei '4711 A-E' würde ich wahrscheinlich einfach sagen: "Pech gehabt" und es zur manuellen Überprüfung geben.
Man läuft beim naiven Splitten natürlich immer Gefahr einige False Positives zu haben. Theoretisch müsste man da wahrscheinlich mit irgendeinem monströsen regulären Ausdruck dran, was dann der Beweis wäre, dass `.rsplit(' ', 1)` im Endeffekt doch keine so gute Idee ist. ^^
Re: Hausnummern und Straßen trennen
Verfasst: Montag 29. Juli 2013, 16:59
von snafu
Hier dann mal ein erster Ansatz mit Regex:
Code: Alles auswählen
import re
def get_house_number(address):
pattern = re.compile(
r'(?<=[ ])\d+(([/-]\d+)|[a-z](-[a-z])?)?$', re.IGNORECASE)
result = pattern.search(address.strip())
if not result:
return ''
return result.group()
Ist gedacht für alle validen (deutschen) Varianten ohne Leerzeichen dazwischen - wobei Dinge wie ½ leider nicht erkennt werden. Zusätze wie "Zimmer 42" funktionieren ebenfalls nicht.
Und hier nochmal in Verbindung mit `.split()`:
Code: Alles auswählen
def get_house_number(address):
house_number = address.split()[-1]
pattern = re.compile(r'\d+(([/-]\d+)|[a-z](-[a-z])?)?$', re.IGNORECASE)
if not pattern.match(house_number):
return ''
return house_number
Sieht zwar kompliziert aus, aber gibt zumindest die Garantie, dass alle automatisch gefundenen Nummern, auch "echte" Hausnummern sind. Wie gesagt: Den Rest müsste man manuell überprüfen. Wie man diese aussortiert, wurde ja schon im Thread beschrieben.
Das einzige, was jetzt noch passieren kann, ist dass ein Straßenname mit einer Zahl endet, diese Zahl mit einem Leerzeichen getrennt wurde und auf diese Zahl (bzw diesen Straßennamen) *keine* Hausnummernangabe folgt. Das heißt der Straßenname "Straße 42" ohne Hausnummernangabe würde falsch behandelt werden.
Re: Hausnummern und Straßen trennen
Verfasst: Donnerstag 1. August 2013, 13:07
von derdon
lunar hat geschrieben:@snafu Vielleicht eher, dass man den Nutzer die Adresse direkt richtig eingeben lässt, oder besser gar nicht erst nach Straße und Hausnummer trennt, wenn es nicht zwingend notwendig ist. Je nach Einzugsbereich der Anwendung gerät man sonst nämlich schnell in Teufels Küche, denn es gibt auch Adresse ohne numerische Hausnummer, oder gar ganz ohne Hausnummer.
Ergänzend dazu der Link
Falsehoods programmers believe about addresses, der verdeutlicht dass man von seiner bisherigen Beobachtung vorschnell auf eine allgemeine Regel schließt (induktive Schlussfolgerung). Es gibt auch andere Seiten mit dem Titel "Falsehoods programmers believe about XY", die ich persönlich sehr interessant und aufschlussreich finde.
Re: Hausnummern und Straßen trennen
Verfasst: Samstag 3. August 2013, 01:57
von Leonidas
derdon hat geschrieben:Ergänzend dazu der Link
Falsehoods programmers believe about addresses, der verdeutlicht dass man von seiner bisherigen Beobachtung vorschnell auf eine allgemeine Regel schließt (induktive Schlussfolgerung).
Falsehoods programmers believe about addresses hat geschrieben:OK, but at the very least you wouldn’t name a town Street
Ich glaube da drängt sich das entsprechende Meme schon direkt auf
Aber danke für den Link, finde ich tatsächlich ziemlich interessant.