Hallo Leute,
ich ziehe mir aus einer CSV-Datei Kontakte heraus. Diese enthalten unter anderem Telefonnummern. Jetzt möchte ich die Nummern vereinheitlichen. Bspw. alle Leerzeichen rausziehen etc. einige eingaben waren bspw auch mit nem Punkt oder auch Simikolon.
Jetzt zu meiner Frage, wie kann ich am sinnvollsten alle nicht numerischen Zeichen aus einem String entfernen?
Tschaui
Drago
PS: Bin noch recht frisch was Python angeht, also habt erbarmen
Telefonnummern ungültige Zeichen entfernen
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi Drago!Dragonito hat geschrieben:Jetzt zu meiner Frage, wie kann ich am sinnvollsten alle nicht numerischen Zeichen aus einem String entfernen?
Es gibt mehrere Möglichkeiten. Suche dir das raus was du brauchst oder kombiniere die Möglichkeiten.
Code: Alles auswählen
>>> tel = "05262/123 123 123 - 15"
>>> print tel.replace("/", "")
05262123 123 123 - 15
>>> print tel.replace(" ", "")
05262/123123123-15
>>> import string
>>> print string.digits
0123456789
>>> print "".join([ char for char in tel if char in string.digits ])
0526212312312315
>>>
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Hi Gerold,
die Säuberung des Strings klappt mittlerweile prima, danke für die Tipps.
Bei der Verarbeitung sind mir allerdings folgende Probleme aufgefallen. Ich habe ein Feld Vorwahl und ein Feld Telefonnummer. Jetzt ist nicht in jedem Feld die Vorwahl gefüllt sondern es kommt auch vor das im Feld Telefonnummern bspw. Die Vorwahl+Telefonnummer+Durchwahl drin hängen. Mal sind diese Daten mit "/" getrennt und dann wieder mit "-". Die Form "vorwahl/telefonnummer" bzw. "vorwahl-telefonnummer" lies sich relativ einfach splitten. Problem ist, ich weiss nicht wann die Nummer genau in den genannten Formaten auftreten. Problematisch gestalltet sich derzeit folgendes Szenario:
vorwahl-telefonnummer-durchwahl.
So wenn ich das splitte bekomme ich nen Tupel mit 3 Inhalten wieder. Meine Idee war es die Anzahl der Tupel zu zählen und dann zu sagen Tupel[0] ist die Vorwahl wenn tupelanzahl > 2. In meinem schlauen Buch habe ich bereits nach einer Funktion gesucht, welche mir die Anzahl der enthaltenen Felder eines Tupels ausgibt, leider bisher ohne erfolg
Wenn das geschafft ist muss ich mir Gedanken machen, wie ich vorgehen soll, wenn das Feld Vorwahl gefüllt ist aber auch das Feld Telefonnummer und dort auch die Vorwahl enthalten ist, hier muss ich im Prinzip gegenprüfen.
Warum können User nicht die Nummer immer richtig eintippen? *schlurchts*
Tschau
Drago
die Säuberung des Strings klappt mittlerweile prima, danke für die Tipps.
Bei der Verarbeitung sind mir allerdings folgende Probleme aufgefallen. Ich habe ein Feld Vorwahl und ein Feld Telefonnummer. Jetzt ist nicht in jedem Feld die Vorwahl gefüllt sondern es kommt auch vor das im Feld Telefonnummern bspw. Die Vorwahl+Telefonnummer+Durchwahl drin hängen. Mal sind diese Daten mit "/" getrennt und dann wieder mit "-". Die Form "vorwahl/telefonnummer" bzw. "vorwahl-telefonnummer" lies sich relativ einfach splitten. Problem ist, ich weiss nicht wann die Nummer genau in den genannten Formaten auftreten. Problematisch gestalltet sich derzeit folgendes Szenario:
vorwahl-telefonnummer-durchwahl.
So wenn ich das splitte bekomme ich nen Tupel mit 3 Inhalten wieder. Meine Idee war es die Anzahl der Tupel zu zählen und dann zu sagen Tupel[0] ist die Vorwahl wenn tupelanzahl > 2. In meinem schlauen Buch habe ich bereits nach einer Funktion gesucht, welche mir die Anzahl der enthaltenen Felder eines Tupels ausgibt, leider bisher ohne erfolg
Wenn das geschafft ist muss ich mir Gedanken machen, wie ich vorgehen soll, wenn das Feld Vorwahl gefüllt ist aber auch das Feld Telefonnummer und dort auch die Vorwahl enthalten ist, hier muss ich im Prinzip gegenprüfen.
Warum können User nicht die Nummer immer richtig eintippen? *schlurchts*
Tschau
Drago
-
- User
- Beiträge: 34
- Registriert: Mittwoch 3. Mai 2006, 12:09
Die Anzahl der Elemente in einer Tupel (und generell) bekommt man über len heraus:Dragonito hat geschrieben: Meine Idee war es die Anzahl der Tupel zu zählen
Code: Alles auswählen
>>>string='1234-5678-90'
>>>tupel=string.split('-')
>>>len(tupel)
3
Zuletzt geändert von rumilmirion am Freitag 19. Mai 2006, 11:23, insgesamt 2-mal geändert.
Du beantwortest Deine Frage ja schon selbst - es sind halt User. *scnr*Warum können User nicht die Nummer immer richtig eintippen?
Und die Länge eines Tupels bestimmst Du ganz einfach mit:
Code: Alles auswählen
>>> t = ( 1, 2, 3)
>>> len(t)
3
>>>
Vielleicht bringt Dich das ja auf Ideen wie Du das bei Dir lösen kannst.
Ciao,
dev
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Hi Dragonito,Dragonito hat geschrieben: Bei der Verarbeitung sind mir allerdings folgende Probleme aufgefallen. Ich habe ein Feld Vorwahl und ein Feld Telefonnummer. Jetzt ist nicht in jedem Feld die Vorwahl gefüllt sondern es kommt auch vor das im Feld Telefonnummern bspw. Die Vorwahl+Telefonnummer+Durchwahl drin hängen. Mal sind diese Daten mit "/" getrennt und dann wieder mit "-". Die Form "vorwahl/telefonnummer" bzw. "vorwahl-telefonnummer" lies sich relativ einfach splitten. Problem ist, ich weiss nicht wann die Nummer genau in den genannten Formaten auftreten.
Drago
erstmal muss ich sagen, dass ich staune ich, in welchem Tempo hier Antworten auf neue Themen folgen. Ich hoffe, mein Beitrag hier ist nicht schon überflüssig.
Zurück zum Thema: sofort als ich das Problem las, viel mir mein Lieblingsgebiet ein: Regular Expressions. Die sind für diese Art von Problemen predestiniert, da sie quasi maßgeschneidert werden können. Ohne viele Worte hier mal mein Lösungsvorschlag:
Code: Alles auswählen
import re, string
## erstelle kompiliertes re-patterns
creSegmentpattern = re.compile(r"((?P<vorwahl>\d+)[/ -])?(?P<nummer>.+?)([- ](?P<durchwahl>\d*))?$")
creZahlpattern = re.compile(r"\d+")
def teile_nummer(sTel):
oResult = creSegmentpattern.match(sTel)
if oResult:
dResult = oResult.groupdict()
dResult["nummer"] = reduce(string.join, creZahlpattern.findall(dResult.get("nummer")))
else:
dResult = {}
print "Telefonnummer mit unzulaessigen Zeichen oder Struktur eingegeben:", sTel
return dResult
print "Geteilte Nummer 1:", teile_nummer("05262/123 123 123 - 15")
print "Geteilte Nummer 2:", teile_nummer("05262/123123123-150")
print "Geteilte Nummer 3:", teile_nummer("05262 12312312315")
print "Geteilte Nummer 4:", teile_nummer("05262-123123123 15")
print "Geteilte Nummer 5:", teile_nummer("0526212312312315")
Was macht das Programm?Ausgabe hat geschrieben:Geteilte Nummer 1: {'durchwahl': '15', 'vorwahl': '05262', 'nummer': '123123123'}
Geteilte Nummer 2: {'durchwahl': '150', 'vorwahl': '05262', 'nummer': '123123123'}
Geteilte Nummer 3: {'durchwahl': None, 'vorwahl': '05262', 'nummer': '12312312315'}
Geteilte Nummer 4: {'durchwahl': '15', 'vorwahl': '05262', 'nummer': '123123123'}
Geteilte Nummer 5: {'durchwahl': None, 'vorwahl': None, 'nummer': '0526212312312315'}
Einfach ausgedrückt: es beginnt vorn und erfasst die erste zusammenhängende Zahl bis zum ersten Leerzeichen, Minus oder Schrägstrich. Sind beide Bedingungen (Zahl und Endzeichen) erfüllt, wird diese Zahl dem Dictionaryschlüssel "vorwahl" zugeordnet. Dann werden alle weiteren Zeichen zusammengefasst und dem Schlüssel "nummer" zugewiesen, so dass am Ende eine Zahl übrig bleibt, die durch ein Leer- oder Minuszeichen von der Hauptnummer getrennt ist (wenn das möglich ist). Diese letzte Zahl wird mit dem Schlüssel "durchwahl" gespeichert. Zum Schluss werden die Sonderzeichen aus "nummer" entfernt.
Wie läuft das ab?
Als erstes werden die RegularExpression Muster kompiliert. Das ist eigentlich nur nötig, wenn man sehr viele Vergleiche damit durchführt, aber da ich nicht weiß, wie viele Einträge Du prüfst, ging ich lieber auf Nummer sicher.
Innerhalb der Funktion wird der als Parameter übergebene String vom Anfang an (match) nach einer Übereinstimmung für das beschriebene Muster durchsucht. Wird ein Muster gefunden, so wird ein Dictionary mit den Teilen zurückgegeben. Das Feld "nummer" kann Leer- und Minuszeichen enthalten. Deshalb werden über die zweite RegularExpression Funktion alle Vorkommen von Zahlen gesucht, die dann durch reduce wieder zu einem String zusammengesetzt werden.
Der verwendete RE Segmentpattern schrittweise erläutert:
r" - definiert als raw-string um sich mehrfache \ zu sparen
( - vorwahlsegment und Trennzeichen in Gruppe zusammenfassen
(?P<vorwahl> - Gruppe mit Label vorwahl definieren, die später über das dictionary abgefragt wird
\d+) - so viele aufeinander folgende Zahlen aufnehmen wie kommen (min. 1), dann Gruppenende
[/ -] - nach der Vorwahl muss ein /, leerzeichen oder - folgen
)? - Gruppe aus Vorwahl und Trennzeichen beendet, ? bedeutet, dass sie einmal oder keinmal vorkommt
(?P<nummer> - Gruppe mit Label nummer definieren
.+? - ein oder mehr beliebige Zeichen erlaubt, ? hinter + bedeutet, dass so wenig wie möglich Zeichen genommen werden
) - Ende der Gruppe nummer
([- ] - Beginn der letzten Gruppe, die mit Minus oder Leerzeichen beginnen muss
(?P<durchwahl> - Gruppe mit Label durchwahl definieren
\d*) - so viele zusammenhängende Zahlen wie möglich aufnehmen
)? - die Durchwahlgruppe kann einmal oder keinmal vorkommen
$" - der zu durchsuchende String muss nach der Durchwahlgruppe zuende sein
Alle Klarheiten beseitigt?
Grüße,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Hi Michel,
danke auch für Deine Antwort. Reguläre Ausdrücke sind mir auch direkt in den Kopf gekommen, habe ich letztendlich nur zum Teil eingesetzt um die Nummern zu "säubern".
Leider sind die Daten, die ich aus der Datenbank bekomme alles andere als Normalisiert. Ich habe zum einen ein Feld Vorwahl, da steht mal was drin, mal steht nix drin. Als Zweites gibt es ein Feld Telefonnummer. Dort steht mal die Nummer ohne Vorwahl drin, mal mit Vorwahl, soweit so gut. Leider gibt es auch die Situation das die Vorwahl ins Vorwahlfeld eingetragen wurde und auch im Feld Telefonnummer die Vorwahl mit drin steht.
Ich bin also hingegangen, habe eine Funktion gebaut, welche das Vorwahlfeld aufnimmt und auch die Telefonnummer. Jetzt prüfe ich als erstes ob eine Vorwahl vorhanden ist. Diese wird sofern vorhanden zwischengespeichert. Als nächstes Prüfe ich ob in der Telefonnummer ggf. die Vorwahl auch vorhanden ist, ist dies der Fall so schneide ich diese ab. Zum Schluss gebe ich die Komplette nummer als Feld[0] Feld[1] zurück... Zwischenzeitlich wird aus den Nummern alles was nicht in eine Telefonnummer gehört rausgefiltert...
Aber selbt dieser Ablauf hilft bei 35000 Adressen nicht viel weiter, ich habe noch Fälle die dann noch die Landesvorwahl drin haben, da habe ich dann aber blockiert solche Datensätze markiere ich als "zu Bearbeiten"... soll der User sich damit rumschlagen Aber ich denke das meiste konnte ich "säubern" immer noch besser als alle Daten neu zu schreiben.
Tschaui
Dragonito
danke auch für Deine Antwort. Reguläre Ausdrücke sind mir auch direkt in den Kopf gekommen, habe ich letztendlich nur zum Teil eingesetzt um die Nummern zu "säubern".
Leider sind die Daten, die ich aus der Datenbank bekomme alles andere als Normalisiert. Ich habe zum einen ein Feld Vorwahl, da steht mal was drin, mal steht nix drin. Als Zweites gibt es ein Feld Telefonnummer. Dort steht mal die Nummer ohne Vorwahl drin, mal mit Vorwahl, soweit so gut. Leider gibt es auch die Situation das die Vorwahl ins Vorwahlfeld eingetragen wurde und auch im Feld Telefonnummer die Vorwahl mit drin steht.
Ich bin also hingegangen, habe eine Funktion gebaut, welche das Vorwahlfeld aufnimmt und auch die Telefonnummer. Jetzt prüfe ich als erstes ob eine Vorwahl vorhanden ist. Diese wird sofern vorhanden zwischengespeichert. Als nächstes Prüfe ich ob in der Telefonnummer ggf. die Vorwahl auch vorhanden ist, ist dies der Fall so schneide ich diese ab. Zum Schluss gebe ich die Komplette nummer als Feld[0] Feld[1] zurück... Zwischenzeitlich wird aus den Nummern alles was nicht in eine Telefonnummer gehört rausgefiltert...
Aber selbt dieser Ablauf hilft bei 35000 Adressen nicht viel weiter, ich habe noch Fälle die dann noch die Landesvorwahl drin haben, da habe ich dann aber blockiert solche Datensätze markiere ich als "zu Bearbeiten"... soll der User sich damit rumschlagen Aber ich denke das meiste konnte ich "säubern" immer noch besser als alle Daten neu zu schreiben.
Tschaui
Dragonito
Michael Schneider,
ich habe Ihre Quellcode angepasst:
TODOs:
1) Ländervorvahle werden nicht immer korrekt erkannt
2) Unit-Test
ich habe Ihre Quellcode angepasst:
Code: Alles auswählen
creSegmentpattern = re.compile(r"((?P<vorwahl>[\+()\d]+)[/ -])?(?P<nummer>.*?)([- ](?P<durchwahl>\d*))?$")
creZahlpattern=re.compile(r"[\s\d-]+")
def teile_nummer(sTel):
try:
oResult = creSegmentpattern.match(sTel)
dResult = oResult.groupdict()
dResult["nummer"] = reduce(string.join, creZahlpattern.findall(dResult.get("nummer")))
except:
dResult = {}
print "Telefonnummer mit unzulaessigen Zeichen oder Struktur eingegeben:", sTel
return dResult
1) Ländervorvahle werden nicht immer korrekt erkannt
2) Unit-Test
Es gibt auch Möglichkeit libphonenumber zu nutzen
Um Java aus Python benutzen zu können, müssen wir JCC installieren:
in setup.py JAVAC = java-6-sun-1.6.0.22 anpassen
Um Java aus Python benutzen zu können, müssen wir JCC installieren:
Code: Alles auswählen
svn co http://svn.apache.org/repos/asf/lucene/pylucene/trunk/jcc jcc
cd jcc
Code: Alles auswählen
python setup.py build
sudo python setup.py install
wget http://libphonenumber.googlecode.com/files/libphonenumber-2.5.1.jar
sudo python -m jcc.__main__ --debug --shared --jar libphonenumber-2.5.1.jar --classpath /home/... --python libphonenumber --install
Code: Alles auswählen
ipython
from my import initVM, CLASSPATH, PhoneNumberUtil
initVM(classpath=CLASSPATH)
pnu = PhoneNumberUtil.getInstance()
pn = pnu.parse(tel, "DE")
fmt = pnu.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL)
Zuletzt geändert von hellboy am Dienstag 15. Februar 2011, 14:59, insgesamt 1-mal geändert.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Oder Jython nutzenhellboy hat geschrieben: Um Java aus Python benutzen zu können, müssen wir ...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@hellboy
Sag mal ist dir schon aufgefallen das der Thread, nun ja letzter Eintrag Ende Mai 2006, tot ist?
Warum hast du nicht ein neuen Thread aufgemacht und dann hierher verlinkt, das dich dieser Thread dazu inspiriert hatte das Thema nochmal anzugehen.
Ich meine ja nur mal Java 6 ist erst im Dezember 2006 rausgekommen und ich denke das Jython nun schon um einiges weiter als JCC ist, oder ?
Sag mal ist dir schon aufgefallen das der Thread, nun ja letzter Eintrag Ende Mai 2006, tot ist?
Warum hast du nicht ein neuen Thread aufgemacht und dann hierher verlinkt, das dich dieser Thread dazu inspiriert hatte das Thema nochmal anzugehen.
Ich meine ja nur mal Java 6 ist erst im Dezember 2006 rausgekommen und ich denke das Jython nun schon um einiges weiter als JCC ist, oder ?
es geht um a Auffindbarkeit des Threads
ich hatte dieselbe Probleme und Thread gefunden mit Schlüsselwort "Vorwahl". Es geht hier auch um
ich hatte dieselbe Probleme und Thread gefunden mit Schlüsselwort "Vorwahl". Es geht hier auch um
die Nummern vereinheitlichen Bspw. alle Leerzeichen rausziehen etc. einige eingaben waren bspw auch mit nem Punkt oder auch Simikolon.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Kommt drauf an. Wenn man eh Jython nutzt, dann erübrigt sich die Frage. Wenn nein, würde ich keines von beiden nehmen, sondern diese - augenscheinlich recht einfache Sache - selber in Python implementierenhellboy hat geschrieben: und was ist in diesem Fall besser?
Jithon vs JCC
Genau das war ja wohl auch mal Sinn des Threads. So schwer sieht mir das jetzt nicht aus - evtl. verkenne ich jetzt aber auch die Komplexität, die Telefonnummern annehmen können.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Bevor man sich irgendwie Java ans Bein bindet, könnte man auch einfach die Python-Portierung von der Bibliothek verwenden: https://github.com/tereno/libphonenumber-Python
@Hyperion:
@Hyperion:
libphonenumber -- Highlights of functionality hat geschrieben:
- Parsing phone numbers for 228 countries/regions, and formatting/validating phone numbers for 196 countries/regions of the world.
- getNumberType - gets the type of the number based on the number itself; able to distinguish Fixed-line, Mobile, Toll-free, Premium Rate, Shared Cost, Voip and Personal Numbers (whenever feasible).
- isNumberMatch - gets a confidence level on whether two numbers could be the same.
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Wenn man JVM installiert hat oder installieren kann. Wenn C-Python installiert ist, dann ist der Umstieg auf Jython, nur um eine Java-Implementierung zu verwenden, für dieses triviale Problem nun wirklich von hinten durch die Brust ins Auge.hellboy hat geschrieben:@BlackJack
selbstverständlich hab ich diese Möglichkeit berücksichtigt und hab versucht auszuprobieren - leider erfolglos.
IMHO Port ist recht jung und in diesem Fall Java-Lib zu nutzen ist einfacher.
:K
Gruß,
Micha
Diese Nachricht zersört sich in 5 Sekunden selbst ...
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Wirkt etwas beschränkt, meinst Du nicht? Dann doch lieber die RegEx.BlackJack hat geschrieben: @Hyperion:libphonenumber -- Highlights of functionality hat geschrieben:
- Parsing phone numbers for 228 countries/regions, and formatting/validating phone numbers for 196 countries/regions of the world.
- getNumberType - gets the type of the number based on the number itself; able to distinguish Fixed-line, Mobile, Toll-free, Premium Rate, Shared Cost, Voip and Personal Numbers (whenever feasible).
- isNumberMatch - gets a confidence level on whether two numbers could be the same.
Diese Nachricht zersört sich in 5 Sekunden selbst ...
- Rebecca
- User
- Beiträge: 1662
- Registriert: Freitag 3. Februar 2006, 12:28
- Wohnort: DN, Heimat: HB
- Kontaktdaten:
Offizielles Python-Tutorial (Deutsche Version)
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei