Parse utilizzabile Indirizzo, Città, Stato, Zip da una stringa

Problema: ho un campo indirizzo da un database Access che è stato convertito in Sql Server 2005. Questo campo ha tutto in un unico campo. Devo analizzare le singole sezioni dell’indirizzo nei loro campi appropriati in una tabella normalizzata. Ho bisogno di farlo per circa 4000 record e deve essere ripetibile.

ipotesi:

  1. Assumi un indirizzo negli Stati Uniti (per ora)

  2. supponiamo che la stringa di input a volte contenga un destinatario (la persona che viene indirizzata) e / o un secondo indirizzo (es. Suite B)

  3. gli stati possono essere abbreviati

  4. il codice postale potrebbe essere standard a 5 cifre o zip + 4

  5. ci sono errori di battitura in alcuni casi

AGGIORNAMENTO: In risposta alle domande poste, gli standard non sono stati seguiti universalmente, ho bisogno di memorizzare i singoli valori, non solo geocodifica e errori significa errore (corretto sopra)

Dati di esempio:

  • AP Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947

  • 11522 Shawnee Road, Greenwood DE 19950

  • 144 Kings Highway, SW Dover, DE 19901

  • Const integrato Servizi 2 Penns Way Suite 405 New Castle, DE 19720

  • Humes Realty 33 Bridle Ridge Court, Lewes, DE 19958

  • Scavo di Nichols 2742 Pulaski Hwy Newark, DE 19711

  • 2284 Bryn Zion Road, Smyrna, DE 19904

  • VEI Dover Crossroads, LLC 1500 Serpentine Road, Suite 100 Baltimore MD 21

  • 580 North Dupont Highway Dover, DE 19901

  • Casella postale 778 Dover, DE 19903

Ho lavorato molto su questo tipo di analisi. Poiché ci sono errori, non otterrai una precisione del 100%, ma ci sono alcune cose che puoi fare per ottenere il massimo da lì, e poi fare un test BS visivo. Ecco il modo generale per farlo. Non è un codice, perché è piuttosto accademico scriverlo, non c’è stranezza, solo un sacco di gestione delle stringhe.

(Ora che hai pubblicato alcuni dati di esempio, ho apportato alcune modifiche minori)

  1. Lavora all’indietro. Inizia dal codice postale, che sarà vicino alla fine e in uno dei due formati noti: XXXXX o XXXXX-XXXX. Se questo non dovesse apparire, puoi presumere che tu sia nella città, parte dello stato, sotto.
  2. La prossima cosa, prima dello zip, sarà lo stato, e sarà sia in formato a due lettere, sia come parole. Sai cosa saranno anche questi – ci sono solo 50 di loro. Inoltre, è ansible eseguire il soundex delle parole per compensare gli errori di ortografia.
  3. prima questa è la città, ed è probabilmente sulla stessa linea dello stato. È ansible utilizzare un database zip-code per controllare la città e lo stato in base allo zip, o almeno usarlo come rilevatore BS.
  4. L’indirizzo stradale sarà generalmente di una o due righe. La seconda linea sarà generalmente il numero di suite se ce n’è una, ma potrebbe anche essere una casella postale.
  5. Sarà quasi imansible rilevare un nome sulla prima o seconda riga, anche se se non è prefisso con un numero (o se è preceduto da un “attn:” o “attenzione a:” potrebbe darti un suggerimento se si tratta di un nome o di una riga di indirizzo.

Spero che questo aiuti un po ‘.

Penso che l’outsourcing del problema sia la cosa migliore: mandalo al geocoder di Google (o Yahoo). Il geocoder restituisce non solo il lat / long (che non interessa qui), ma anche un ricco parsing dell’indirizzo, con campi compilati che non hai inviato (incluso ZIP + 4 e county).

Ad esempio, analizza le rese “1600 Amphitheatre Parkway, Mountain View, CA”

{ "name": "1600 Amphitheatre Parkway, Mountain View, CA, USA", "Status": { "code": 200, "request": "geocode" }, "Placemark": [ { "address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", "AddressDetails": { "Country": { "CountryNameCode": "US", "AdministrativeArea": { "AdministrativeAreaName": "CA", "SubAdministrativeArea": { "SubAdministrativeAreaName": "Santa Clara", "Locality": { "LocalityName": "Mountain View", "Thoroughfare": { "ThoroughfareName": "1600 Amphitheatre Pkwy" }, "PostalCode": { "PostalCodeNumber": "94043" } } } } }, "Accuracy": 8 }, "Point": { "coordinates": [-122.083739, 37.423021, 0] } } ] } 

Ora è parseable!

Il poster originale è probabilmente passato da molto tempo, ma mi sono preso gioco del porting del Perl Geo :: StreetAddress: il modulo US usato da geocoder.us in C #, lo ha scaricato su CodePlex e penso che le persone che inciampano in questa domanda in futuro possano trovalo utile:

Parser degli indirizzi degli Stati Uniti

Nella home page del progetto, cerco di parlare dei suoi limiti (molto reali). Poiché non è supportato dal database USPS di indirizzi stradali validi, l’analisi può essere ambigua e non può confermare né negare la validità di un determinato indirizzo. Può solo provare a estrarre i dati dalla stringa.

È concepito per il caso in cui è necessario ottenere un set di dati per lo più nei campi corretti o si desidera fornire una scorciatoia per l’immissione dei dati (lasciando che gli utenti incollino un indirizzo in una casella di testo anziché inserire tabulazioni in più campi). Non è pensato per verificare la deliverability di un indirizzo.

Non tenta di analizzare qualcosa al di sopra della linea della strada, ma è probabile che uno possa fare a meno della regex per ottenere qualcosa di ragionevolmente vicino – probabilmente lo romperò solo al numero civico.

L’ho fatto in passato.

O fallo manualmente (costruisci un bel gui che aiuti l’utente a farlo rapidamente) o automatizzalo e verificalo con un database di indirizzi recenti (devi comprarlo) e mantieni manualmente gli errori.

La movimentazione manuale richiederà circa 10 secondi ciascuno, il che significa che puoi fare 3600/10 = 360 all’ora, quindi 4000 impiegano circa 11-12 ore. Questo ti darà un alto tasso di precisione.

Per l’automazione, è necessario un recente database degli indirizzi negli Stati Uniti e modificare le regole a tale scopo. Suggerisco di non andare alla fantasia sulla regex (difficile da mantenere a lungo termine, così tante eccezioni). Vai per il 90% di corrispondenza con il database, fai il resto manualmente.

Ottieni una copia degli standard di indirizzamento postale (USPS) su http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf e nota che è lunga più di 130 pagine. I regex da implementare sarebbero pazzeschi.

Per gli indirizzi internazionali, tutte le scommesse sono distriggerste. I lavoratori con sede negli Stati Uniti non sarebbero in grado di convalidare.

In alternativa, utilizzare un servizio dati. Tuttavia, non ho raccomandazioni.

Inoltre: quando invii le cose per posta (è questo il motivo, giusto?) Assicurati di mettere “la correzione dell’indirizzo richiesto” sulla busta (nel posto giusto) e aggiorna il database. (Abbiamo fatto una semplice gui per la persona della reception per farlo, la persona che in realtà ordina tramite la posta)

Infine, quando hai effettuato il lavaggio dei dati, cerca i duplicati.

Ho lavorato nel dominio di elaborazione degli indirizzi per circa 5 anni, e non c’è davvero un proiettile d’argento. La soluzione corretta dipenderà dal valore dei dati. Se non è molto prezioso, lanciatelo attraverso un parser come suggeriscono le altre risposte. Se è anche un po ‘prezioso, avrai sicuramente bisogno di una valutazione umana / correggere tutti i risultati del parser. Se stai cercando una soluzione completamente automatizzata e ripetibile, probabilmente vorrai parlare con un fornitore di correzioni di indirizzi come Group1 o Trillium.

Dopo il consiglio qui, ho escogitato la seguente funzione in VB che crea passabili, sebbene non sempre perfetti (se viene fornito un nome di società e una linea di suite, combina i dati utilizzabili della suite e della città). Non esitate a commentare / refactoring / urlato contro di me per aver infranto una delle mie regole, ecc .:

 Public Function parseAddress(ByVal input As String) As Collection input = input.Replace(",", "") input = input.Replace(" ", " ") Dim splitString() As String = Split(input) Dim streetMarker() As String = New String() {"street", "st", "st.", "avenue", "ave", "ave.", "blvd", "blvd.", "highway", "hwy", "hwy.", "box", "road", "rd", "rd.", "lane", "ln", "ln.", "circle", "circ", "circ.", "court", "ct", "ct."} Dim address1 As String Dim address2 As String = "" Dim city As String Dim state As String Dim zip As String Dim streetMarkerIndex As Integer zip = splitString(splitString.Length - 1).ToString() state = splitString(splitString.Length - 2).ToString() streetMarkerIndex = getLastIndexOf(splitString, streetMarker) + 1 Dim sb As New StringBuilder For counter As Integer = streetMarkerIndex To splitString.Length - 3 sb.Append(splitString(counter) + " ") Next counter city = RTrim(sb.ToString()) Dim addressIndex As Integer = 0 For counter As Integer = 0 To streetMarkerIndex If IsNumeric(splitString(counter)) _ Or splitString(counter).ToString.ToLower = "po" _ Or splitString(counter).ToString().ToLower().Replace(".", "") = "po" Then addressIndex = counter Exit For End If Next counter sb = New StringBuilder For counter As Integer = addressIndex To streetMarkerIndex - 1 sb.Append(splitString(counter) + " ") Next counter address1 = RTrim(sb.ToString()) sb = New StringBuilder If addressIndex = 0 Then If splitString(splitString.Length - 2).ToString() <> splitString(streetMarkerIndex + 1) Then For counter As Integer = streetMarkerIndex To splitString.Length - 2 sb.Append(splitString(counter) + " ") Next counter End If Else For counter As Integer = 0 To addressIndex - 1 sb.Append(splitString(counter) + " ") Next counter End If address2 = RTrim(sb.ToString()) Dim output As New Collection output.Add(address1, "Address1") output.Add(address2, "Address2") output.Add(city, "City") output.Add(state, "State") output.Add(zip, "Zip") Return output End Function Private Function getLastIndexOf(ByVal sArray As String(), ByVal checkArray As String()) As Integer Dim sourceIndex As Integer = 0 Dim outputIndex As Integer = 0 For Each item As String In checkArray For Each source As String In sArray If source.ToLower = item.ToLower Then outputIndex = sourceIndex If item.ToLower = "box" Then outputIndex = outputIndex + 1 End If End If sourceIndex = sourceIndex + 1 Next sourceIndex = 0 Next Return outputIndex End Function 

Passando alla funzione parseAddress “AP Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947” restituisce:

 2299 Lewes-Georgetown Hwy AP Croll & Son Georgetown DE 19947 

SmartyStreets ha una nuova funzionalità che estrae gli indirizzi da stringhe di input arbitrarie. (Nota: non lavoro su SmartyStreets.)

Ha estratto con successo tutti gli indirizzi dall’input di esempio indicato nella domanda precedente. (A proposito, solo 9 di questi 10 indirizzi sono validi.)

Ecco alcuni degli output: inserisci la descrizione dell'immagine qui

Ed ecco l’output in formato CSV della stessa richiesta:

 ID,Start,End,Segment,Verified,Candidate,Firm,FirstLine,SecondLine,LastLine,City,State,ZIPCode,County,DpvFootnotes,DeliveryPointBarcode,Active,Vacant,CMRA,MatchCode,Latitude,Longitude,Precision,RDI,RecordType,BuildingDefaultIndicator,CongressionalDistrict,Footnotes 1,32,79,"2299 Lewes-Georgetown Hwy, Georgetown, DE 19947",N,,,,,,,,,,,,,,,,,,,,,, 2,81,119,"11522 Shawnee Road, Greenwood DE 19950",Y,0,,11522 Shawnee Rd,,Greenwood DE 19950-5209,Greenwood,DE,19950,Sussex,AABB,199505209226,Y,N,N,Y,38.82865,-75.54907,Zip9,Residential,S,,AL,N# 3,121,160,"144 Kings Highway, SW Dover, DE 19901",Y,0,,144 Kings Hwy,,Dover DE 19901-7308,Dover,DE,19901,Kent,AABB,199017308444,Y,N,N,Y,39.16081,-75.52377,Zip9,Commercial,S,,AL,L# 4,190,232,"2 Penns Way Suite 405 New Castle, DE 19720",Y,0,,2 Penns Way Ste 405,,New Castle DE 19720-2407,New Castle,DE,19720,New Castle,AABB,197202407053,Y,N,N,Y,39.68332,-75.61043,Zip9,Commercial,H,,AL,N# 5,247,285,"33 Bridle Ridge Court, Lewes, DE 19958",Y,0,,33 Bridle Ridge Cir,,Lewes DE 19958-8961,Lewes,DE,19958,Sussex,AABB,199588961338,Y,N,N,Y,38.72749,-75.17055,Zip7,Residential,S,,AL,L# 6,306,339,"2742 Pulaski Hwy Newark, DE 19711",Y,0,,2742 Pulaski Hwy,,Newark DE 19702-3911,Newark,DE,19702,New Castle,AABB,197023911421,Y,N,N,Y,39.60328,-75.75869,Zip9,Commercial,S,,AL,A# 7,341,378,"2284 Bryn Zion Road, Smyrna, DE 19904",Y,0,,2284 Bryn Zion Rd,,Smyrna DE 19977-3895,Smyrna,DE,19977,Kent,AABB,199773895840,Y,N,N,Y,39.23937,-75.64065,Zip7,Residential,S,,AL,A#N# 8,406,450,"1500 Serpentine Road, Suite 100 Baltimore MD",Y,0,,1500 Serpentine Rd Ste 100,,Baltimore MD 21209-2034,Baltimore,MD,21209,Baltimore,AABB,212092034250,Y,N,N,Y,39.38194,-76.65856,Zip9,Commercial,H,,03,N# 9,455,495,"580 North Dupont Highway Dover, DE 19901",Y,0,,580 N DuPont Hwy,,Dover DE 19901-3961,Dover,DE,19901,Kent,AABB,199013961803,Y,N,N,Y,39.17576,-75.5241,Zip9,Commercial,S,,AL,N# 10,497,525,"PO Box 778 Dover, DE 19903",Y,0,,PO Box 778,,Dover DE 19903-0778,Dover,DE,19903,Kent,AABB,199030778781,Y,N,N,Y,39.20946,-75.57012,Zip5,Residential,P,,AL, 

Ero lo sviluppatore che ha originariamente scritto il servizio. L’algoritmo che abbiamo implementato è un po ‘diverso da qualsiasi risposta specifica qui, ma ogni indirizzo estratto viene verificato rispetto all’API di ricerca degli indirizzi, quindi puoi essere sicuro che sia valido o meno. Ogni risultato verificato è garantito, ma sappiamo che gli altri risultati non saranno perfetti perché, come è stato reso abbondantemente chiaro in questa discussione, gli indirizzi sono imprevedibili, anche a volte per gli umani.

Questo non risolverà il tuo problema, ma se hai solo bisogno di dati lat / long per questi indirizzi, l’API di Google Maps analizzerà abbastanza bene gli indirizzi non formattati.

Buon suggerimento, in alternativa puoi eseguire una richiesta CURL per ogni indirizzo su Google Maps e restituirà l’indirizzo correttamente formattato. Da ciò, è ansible regex al contenuto del tuo cuore.

+1 sulla soluzione suggerita da James A. Rosen in quanto ha funzionato bene per me, tuttavia per i completisti questo sito è una lettura affascinante e il miglior tentativo che ho visto nella documentazione degli indirizzi in tutto il mondo: http://www.columbia.edu/kermit /postal.html

Ci sono degli standard nel modo in cui gli indirizzi sono registrati? Per esempio:

  1. Ci sono sempre virgole o nuove linee che separano street1 da street2 da città a stato da zip?
  2. I tipi di indirizzo (strada, strada, viale, ecc.) Sono sempre indicati? sempre abbreviato? Alcuni di ciascuno?
  3. Definisci “errore”.

La mia risposta generale è una serie di espressioni regolari, anche se la complessità dipende dalla risposta. E se non c’è alcuna coerenza, allora si può essere in grado di ottenere un parziale successo con un Regex (cioè: filtrare il codice postale e lo stato) e dovrà fare il resto a mano (o almeno passare il resto molto bene attentamente per essere sicuro di individuare gli errori).

Un’altra richiesta di dati di esempio.

Come è stato detto avrei lavorato indietro dallo zip.

Una volta creato un file zip, interrogherò un database zip, memorizzerò i risultati e rimuoverli e lo zip dalla stringa.

Questo ti lascerà con il pasticcio di indirizzo. Gli indirizzi MOST (Tutti?) Inizieranno con un numero, quindi trova la prima occorrenza di un numero nella stringa rimanente e recupera tutto da esso alla (nuova) fine della stringa. Questo sarà il tuo indirizzo. Qualunque cosa alla sinistra di quel numero è probabilmente un destinatario.

Ora dovresti avere la città, lo stato e lo zip memorizzati in una tabella e possibilmente due stringhe, indirizzo e indirizzo. Per l’indirizzo, verificare l’esistenza di “Suite” o “App.” ecc. e diviso in due valori (indirizzo 1 e 2).

Per il destinatario punterei e afferro l’ultima parola di quella stringa come cognome e metto il resto nel campo del primo nome. Se non vuoi farlo, dovrai verificare il saluto (Mr., Ms., Dr., ecc.) All’inizio e fare alcune ipotesi basate sul numero di spazi su come il nome è costituita.

Non penso che esista un modo per analizzare con precisione al 100%.

Prova http://www.address-parser.com . Usiamo il loro servizio web, che puoi testare online

In base ai dati di esempio:

  1. Vorrei iniziare alla fine della stringa. Analizza un codice postale (in entrambi i formati). Leggi la fine del primo spazio. Se non è stato trovato alcun codice postale Errore.

  2. Taglia la fine quindi per spazi e caratteri speciali (virgole)

  3. Quindi passare a Stato, utilizzare nuovamente lo spazio come delimitatore. Forse utilizzare un elenco di ricerca per convalidare 2 codici di stato lettera e nomi di stato completo. Se non è stato trovato uno stato valido, errore.

  4. Tagliare nuovamente gli spazi e le virgole dalla fine.

  5. La città diventa complicata, in realtà utilizzerei una virgola qui, col rischio di ottenere troppi dati in città. Cerca la virgola o l’inizio della riga.

  6. Se nella stringa sono ancora presenti caratteri, inserire tutto ciò in un campo indirizzo.

Questo non è perfetto, ma dovrebbe essere un buon punto di partenza.

Se si tratta di dati umani inseriti, passerai troppo tempo a cercare di codificare le eccezioni.

Provare:

  1. Espressione regolare per estrarre il codice postale

  2. Ricerca del codice postale (tramite il DB di governo appropriato) per ottenere l’indirizzo corretto

  3. Chiedi a uno stagista di verificare manualmente che i nuovi dati corrispondano al vecchio

Questo non risolverà il tuo problema, ma se hai solo bisogno di dati lat / long per questi indirizzi, l’API di Google Maps analizzerà abbastanza bene gli indirizzi non formattati.

RecogniContact è un object COM di Windows che analizza gli indirizzi statunitensi ed europei. Puoi provarlo direttamente su http://www.loquisoft.com/index.php?page=8

Potresti voler controllare questo !! http://jgeocoder.sourceforge.net/parser.html Ha funzionato come un fascino per me.

Questo tipo di problema è difficile da risolvere a causa delle ambiguità sottostanti nei dati.

Ecco una soluzione basata su Perl che definisce un albero grammaticale ricorsivo di discesa basato su espressioni regolari per analizzare molte combinazioni valide di indirizzi stradali: http://search.cpan.org/~kimryan/Lingua-EN-AddressParse-1.20/lib/Lingua /EN/AddressParse.pm . Ciò include le proprietà secondarie all’interno di un indirizzo come: 12 1st Avenue N Suite # 2 Da qualche parte CA 12345 USA

È simile a http://search.cpan.org/~timb/Geo-StreetAddress-US-1.03/US.pm menzionato sopra, ma funziona anche per indirizzi che non provengono dagli Stati Uniti, come il Regno Unito, l’Australia e Canada.

Ecco l’output per uno dei tuoi indirizzi di esempio. Si noti che la sezione del nome dovrebbe essere prima rimossa da “AP Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947” per ridurlo a “2299 Lewes-Georgetown Hwy, Georgetown, DE 19947”. Questo è facilmente raggiungibile rimuovendo tutti i dati fino al primo numero trovato nella stringa.

 Non matching part '' Error '0' Error descriptions '' Case all '2299 Lewes-Georgetown Hwy Georgetown DE 19947' COMPONENTS '' country '' po_box_type '' post_box '' post_code '19947' pre_cursor '' property_identifier '2299' property_name '' road_box '' street 'Lewes-Georgetown' street_direction '' street_type 'Hwy' sub_property_identifier '' subcountry 'DE' suburb 'Georgetown' 

Dal momento che c’è una possibilità di errore nella parola, pensa di usare SOUNDEX combinato con l’algoritmo LCS per confrontare le stringhe, questo aiuterà molto!

usando l’API di google

 $d=str_replace(" ", "+", $address_url); $completeurl ="http://maps.googleapis.com/maps/api/geocode/xml?address=".$d."&sensor=true"; $phpobject = simplexml_load_file($completeurl); print_r($phpobject); 

Per gli sviluppatori di rubini o rails c’è una bella gem disponibile chiamata street_address . Ho usato questo su uno dei miei progetti e fa il lavoro che mi serve.

L’unico problema che ho avuto è stato ogni volta che un indirizzo è in questo formato PO Box 1410 Durham, NC 27702 restituito nullo e quindi ho dovuto sostituire “Casella postale” con “” e dopo questo è stato in grado di analizzarlo.

Ci sono servizi di dati che dato un codice postale ti forniranno un elenco di nomi di strade in quel codice di avviamento postale.

Usa una espressione regolare per estrarre Zip o City State: trova quello corretto o se un errore ottiene entrambi. estrai l’elenco delle strade da una sorgente dati Correggi città e stato, quindi l’indirizzo. Una volta ottenuto un indirizzo valido per la linea 1, città, stato e zip, è ansible formulare ipotesi sulla linea indirizzo 2..3

Non so QUANTO SIA FATTO, ma non ho visto questo, quindi ho pensato di andare avanti e suggerire questo:

Se sei rigorosamente negli Stati Uniti … ottieni un enorme database di tutti i codici postali, gli stati, le città e le strade. Ora cerca questi nei tuoi indirizzi. Puoi convalidare ciò che trovi provando se, per esempio, la città che hai trovato esiste nello stato che hai trovato, o controllando se la strada che hai trovato esiste nella città che hai trovato. In caso contrario, è probabile che John non è per la strada di John, ma è il nome del destinatario … Fondamentalmente, ottenere il maggior numero di informazioni ansible e controllare i propri indirizzi contro di essa. Un esempio estremo potrebbe essere quello di ottenere UNA LISTA DI TUTTI GLI INDIRIZZI NEGLI STATI UNITI DI A e quindi scoprire quale ha la corrispondenza più pertinente con ciascuno dei tuoi indirizzi …

C’è la porta javascript di perl Geo :: StreetAddress :: pacchetto USA: https://github.com/hassansin/parse-address . È basato su regex e funziona abbastanza bene.