2012-03-30 4 views
0

Dieses einfache Problem ist mich zu töten. Ich habe vorher etwas über den Versuch gepostet, eine Datenbank mit Adressen zu bereinigen, und jemand schlug GeoPy vor, die Gültigkeit der Adressen zu überprüfen. Tolles Tool, das ich nicht kannte, aber bevor ich das mache, muss ich die Datenbank ein wenig aufräumen, da geopy sich nicht um unordentliche Formatierungen kümmert. Die Lösung besteht darin, reguläre Ausdrücke zu verwenden, von denen ich denke, dass sie für die meisten Adresstypen, die ich in der Datenbank gesehen habe, behoben wurden. Dennoch habe ich Probleme mit der letzten RegExp ich definiert (im Code r4 genannt), weil es einen Teil der ersten Klammer, die ich nicht brauche, neu abstimmen, und ich weiß nicht, warum ich ein extra Leerzeichen habe wenn es die letzte Gruppe zurückgibt (Stadt: London, Land: England). Kann jemand helfen?Reguläre Ausdrücke in Python. Kann jemand einem Neuling helfen?

import re 

r1 = '\s*ForeignZip.*--\s*([\d\.]+)' 
r2 = '(\w+)\W*,\W*(\w*)' 
r3 = '(?<=\().*?(?=\))' 
r4 = '(\w+\W\()' 

Location = [' ForeignZip (xxx) -- 734.450','Washington, DC.','London (England)'] 

for item in Location: 
    print item 
    match1 = re.search(r1,item) 
    match2 = re.search(r2,item) 
    match3 = re.search(r3,item) 
    match4 = re.search(r4,item) 

    if match1: 
     print 'pattern 1 found:', match1.group(1) 

    elif match2: 
     print 'pattern 2 found: City :' + match2.group(1) + ", State :" + match2.group(2) 

    elif match3: 
     print 'pattern 3 found: City: ', match4.group() + ", Country :" + match3.group(0) 

    else: 
     print 'no match' 

Das gibt

ForeignZip (xxx) -- 734.450 
pattern 1 found: 734.50 
Washington, DC. 
pattern 2 found: City :Washington, State :DC 
London (England) 
pattern 3 found: City: London (, Country :England 
+1

Ihr Hauptproblem ist das '\ (' is * i nside * Ihre Fanggruppe. Wenn Sie es nicht in die Erfassungsgruppe aufnehmen möchten, es aber dennoch zur Übereinstimmung verwenden möchten, platzieren Sie es außerhalb der Klammern in Ihrer Regex. Außerdem ist es ineffizient, alle 4 Muster zu bewerten. Warum überprüfen Sie nicht, ob eine Übereinstimmung gefunden wird, nachdem jede Regex ausgeführt wurde. Wenn Sie also eine Übereinstimmung mit dem ersten Muster finden, können Sie die Auswertung aller übrigen Muster vermeiden. –

Antwort

2

Nur ein wenig Wechsel Ihres später Regexes ist notwendig ... Es gibt wahrscheinlich eine Million Möglichkeiten, dies zu tun, aber hier ist ein .:

r3 = r'(\w+)\s+\((\w+)\)' #Match a word (group1), whitespace followed by a '(' then another word (group2) and finally a closing ')' 

oder Leerzeichen völlig unbedeutend zu machen:

r3 = r'(\s*(?:\w+\s*)*)\s*\(\s*((?:\w+\s*)+)\s*\)' 

, die im Grunde ist die vorherige Regex außer es \w+ mit (?:\w+\s*)* ersetzt, die mehrere Wörter ermöglicht werden angepasst, aber nicht die Kappe ture sie - es lässt die "Gruppen" gleich, da (?:...) nie die Zeichenkette speichert, die es überall passte.

und nun den dritten Test ändern:

elif match3: 
    print 'pattern 3 found: City : '+ match3.group(1) + ", Country :" + match3.group(2) 

I entfernt r4 auch, da es nicht mehr notwendig ist ... (Auch das geändert ‚‘ zu einem ‚+‘ für Konsistenz und hinzugefügt ein Raum in ‚Stadt:‘.)

beachten sie auch, dass, wenn sie mit Regex zu tun, ist es oft schön ist „raw“ Strings zu verwenden (dies verhindert, dass python-Tokens in der Zeichenfolge Mangeln den Unterschied zu testen, versuchen:

print ("\n") #prints newline 
print (r"\n") #prints "\n" 
+0

Großartig !! Danke für die Rückmeldung! –

+0

Sicher, kein Problem. Seien Sie sicher, die andere Antwort auch zu sehen ... Sie erklären das Verhalten, das Sie sehr gut erhielten (besonders warum Sie eine hintere Klammer hatten). Ich habe meine Antwort genau so geschrieben, wie ich es getan habe, weil es so aussieht als wäre es eine Verschwendung, 2 Re (mit Lookahead und Lookbehind - Yuck) zu verwenden, wenn nur einer den Trick macht (ohne Lookahead/Behind). – mgilson

+0

Ich stimme dir zu. Eins ist gut! – varunl

1

Lassen Sie uns an aussehen:

(\w+\W\() 

Zuerst Sie eine Referenz mit den äußersten Pars zu etwas zu speichern, das Spiel in ihnen ist, so:

\w+\W\(

... Hinweis die \( - die

auch eine wörtliche offenen paren passt, ich bin nicht ein Python-Typ, aber ist das Komma hier angeblich zufällig ein Pluszeichen sein?

City: ', match4.group() + ... 
1

Es gibt die Klammer, weil es einen Teil des Musters ist: \(

Sie könnten dies tun:

r4 = '(\w+\W)\(' 
[...] 
print 'pattern 3 found: City: ', match4.group(1) 
2

ändern r4 an folgenden

r4 = '\w+\W' 

auch in,

elif match3: 
     print 'pattern 3 found: City: ', match4.group() + ", Country :" + match3.group(0) 

Sie haben ein "," nach City anstelle eines "+" eingefügt, das den Leerraum setzt. Ändern Sie es wie folgt.

elif match3: 
     print 'pattern 3 found: City: ' + match4.group() + ", Country :" + match3.group(0) 
+0

Danke! Ich hatte das "," nicht bemerkt. Tolles Feedback! –

1
  1. re.compile beschleunigt alles, wenn Sie in einer Schleife
  2. große reguläre Ausdrücke sind
  3. eine Gruppe dict können Sie unglaublich effizient sagen, wo Sie etwas
  4. gefunden

#

finder = re.compile('\s*ForeignZip.*--\s*(?P<fzip>[\d\.]+)|(?P<uscity>\w+)\W*,\W*(?P<state>\w*)|(?P<fcity>\w+)\W*\((?P<country>\w*)\)') 
[finder.match(l).groupdict() for l in ll] 

returns:

[{'country': None, 
    'fcity': None, 
    'fzip': '734.450', 
    'state': None, 
    'uscity': None}, 
{'country': None, 
    'fcity': None, 
    'fzip': None, 
    'state': 'DC', 
    'uscity': 'Washington'}, 
{'country': 'England', 
    'fcity': 'London', 
    'fzip': None, 
    'state': None, 
    'uscity': None}] 
+0

Ausgezeichnete Lösung. Diese Vorlage wird mir in anderen Teilen meines Projekts sehr helfen. Vielen Dank. Prost! –