Domanda

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 campi appropriati in una tabella normalizzata.Devo farlo per circa 4.000 record e deve essere ripetibile.

Presupposti:

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

  2. presupporre che la stringa di input a volte contenga un destinatario (la persona a cui ci si rivolge) e/o un secondo indirizzo (ad es.Suite B)

  3. gli stati possono essere abbreviati

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

  5. in alcuni casi ci sono errori di battitura

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

Dati di esempio:

  • UN.P.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947

  • 11522 Shawnee Road, Greenwood DE 19950

  • 144 Kings Highway, sud-ovestDover, DE 19901

  • Cost. IntegrataServizi 2 Penns Way Suite 405 New Castle, DE 19720

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

  • Scavo Nichols 2742 Pulaski Hwy Newark, DE 19711

  • 2284 Bryn Zion Road, Smirne, DE 19904

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

  • 580 North Dupont Highway Dover, DE 19901

  • P.O.Casella 778 Dover, DE 19903

È stato utile?

Soluzione

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 la maggior parte del percorso, quindi eseguire un test visivo BS.Ecco il modo generale di procedere.Non è codice, perché è piuttosto accademico scriverlo, non c'è stranezza, solo molta gestione delle stringhe.

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

  1. Lavora all'indietro.Inizia dal codice postale, che sarà vicino alla fine, e in uno dei due formati noti:XXXXX o XXXX-XXXX.Se questo non appare, puoi presumere di trovarti nella città, parte dello stato, di seguito.
  2. La cosa successiva, prima dello zip, sarà lo stato, e sarà in formato due lettere o in parole.Sai anche quali saranno: ce ne sono solo 50.Inoltre, potresti far risuonare le parole per compensare gli errori di ortografia.
  3. prima c'è la città, ed è probabilmente sulla stessa linea dello Stato.Potresti usare a database dei codici postali per controllare la città e lo stato in base al codice postale, o almeno usarlo come rilevatore di BS.
  4. L'indirizzo stradale sarà generalmente composto da una o due righe.La seconda riga sarà generalmente il numero della suite, se presente, ma potrebbe anche essere una casella postale.
  5. Sarà quasi impossibile rilevare un nome sulla prima o sulla seconda riga, tuttavia se non è preceduto da un numero (o se ha il prefisso "attn:" o "attenzione a:" potrebbe darti un suggerimento come se si tratta di un nome o di una riga di indirizzo.

Spero che questo aiuti in qualche modo.

Altri suggerimenti

Penso che esternalizzare il problema sia la soluzione migliore:inviarlo al geocoder di Google (o Yahoo).Il geocodificatore restituisce non solo la latitudine/longitudine (che non interessano qui), ma anche un'analisi approfondita dell'indirizzo, con i campi compilati che non hai inviato (inclusi CAP+4 e contea).

Ad esempio, l'analisi di "1600 Amphitheatre Parkway, Mountain View, CA" restituisce il risultato

{
  "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 quello è analizzabile!

Il poster originale è probabilmente cambiato da tempo, ma ho provato a trasferire il Perl Geo::Indirizzo:USA modulo utilizzato da geocoder.us in C#, l'ho scaricato su CodePlex e penso che le persone che si imbatteranno in questa domanda in futuro potrebbero trovarla utile:

Analizzatore di indirizzi USA

Nella home page del progetto, provo a parlare dei suoi (molto reali) limiti.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ò semplicemente provare a estrarre i dati dalla stringa.

È pensato per il caso in cui è necessario ottenere una serie di dati principalmente nei campi giusti o si desidera fornire una scorciatoia per l'immissione dei dati (consentendo agli utenti di incollare un indirizzo in una casella di testo anziché scorrere più campi con la scheda).È non destinato a verificare la consegnabilità di un indirizzo.

Non tenta di analizzare nulla al di sopra della linea stradale, ma probabilmente si potrebbe manipolare la regex per ottenere qualcosa di ragionevolmente vicino: probabilmente lo interromperei semplicemente al numero civico.

L'ho fatto in passato.

Fallo manualmente (crea una bella GUI che aiuti l'utente a farlo rapidamente) oppure automatizzalo e confrontalo con un database di indirizzi recente (devi acquistarlo) e gestisci manualmente gli errori.

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

Per l'automazione, tu Bisogno un recente database di indirizzi degli Stati Uniti e modificare le regole in base a ciò.Suggerisco di non esagerare con le espressioni regolari (difficile da mantenere a lungo termine, così tante eccezioni).Scegli una corrispondenza del 90% rispetto al database, fai il resto manualmente.

Ottieni una copia degli standard di indirizzamento postale (USPS) all'indirizzo http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf e nota che è lungo più di 130 pagine.Le espressioni regolari per implementarlo sarebbero pazze.

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

In alternativa, utilizzare un servizio dati.Non ho però consigli.

Inoltre:quando invii il materiale per posta (è a questo che serve, vero?) assicurati di inserire "richiesta correzione dell'indirizzo" sulla busta (nel posto giusto) e aggiornamento la banca dati.(Abbiamo creato una semplice interfaccia grafica per l'addetto alla reception a tale scopo;la persona che effettivamente smista la posta)

Infine, dopo aver cancellato i dati, cerca i duplicati.

Dopo il consiglio qui, ho ideato la seguente funzione in VB che crea dati passabili, anche se non sempre perfetti (se vengono forniti il ​​nome di un'azienda e una linea di suite, combina la suite e la città) utilizzabili.Sentitevi liberi di commentare/refactoring/sgridarmi 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 il parseAddress funzione "A.P.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947" restituisce:

2299 Lewes-Georgetown Hwy
A. P. Croll & Son  
Georgetown
DE
19947

Lavoro nel campo dell'elaborazione degli indirizzi ormai da circa 5 anni e non esiste davvero una soluzione miracolosa.La soluzione corretta dipenderà dal valore dei dati.Se non è molto prezioso, passalo attraverso un parser come suggeriscono le altre risposte.Se è anche piuttosto prezioso, avrai sicuramente bisogno che un essere umano valuti/corregga tutti i risultati del parser.Se stai cercando una soluzione completamente automatizzata e ripetibile, probabilmente vorrai parlare con un fornitore di correzione di indirizzi come Group1 o Trillium.

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

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

Ecco alcuni dei risultati:enter image description here

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, S.W. 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,"P.O. 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 originariamente ha scritto il servizio.L'algoritmo che abbiamo implementato è leggermente 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 fatto abbondantemente chiaro in questo thread, gli indirizzi sono imprevedibili, a volte anche per gli umani.

Questo non risolverà il tuo problema, ma se hai bisogno solo di dati LAT/Long per questi indirizzi, l'API di Google Maps analizzerà abbastanza bene gli indirizzi non formati.

Buon suggerimento, in alternativa puoi eseguire una richiesta CURL per ciascun indirizzo a Google Maps e restituirà l'indirizzo correttamente formattato.Da ciò, puoi regex a tuo piacimento.

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

Esistono degli standard per quanto riguarda la registrazione degli indirizzi?Per esempio:

  1. Ci sono sempre virgole o nuove righe che separano street1 da street2 da city da state a zip?
  2. I tipi di indirizzo (strada, via, viale, ecc.) sono sempre specificati?sempre abbreviato?Alcuni di ciascuno?
  3. Definire "errore".

La mia risposta generale è una serie di espressioni regolari, sebbene la complessità dipenda dalla risposta.E se non c'è alcuna coerenza, potresti riuscire a ottenere solo un successo parziale con un Regex (ovvero:filtrando codice postale e stato) e dovrà fare il resto a mano (o almeno esaminare il resto con molta attenzione per assicurarsi di individuare gli errori).

Un'altra richiesta di dati campione.

Come è stato accennato, lavorerei all'indietro partendo dallo zip.

Una volta ottenuto uno zip, interrogherei un database zip, memorizzerei i risultati e li rimuoverei insieme allo zip dalla stringa.

Questo ti lascerà con il caos degli indirizzi.LA MAGGIOR PARTE degli indirizzi (tutti?) inizieranno con un numero, quindi trova la prima occorrenza di un numero nella stringa rimanente e prendi tutto da esso fino alla (nuova) fine della stringa.Quello sarà il tuo indirizzo.Qualunque cosa a sinistra di quel numero è probabilmente un destinatario.

Ora dovresti avere la città, lo stato e il codice postale memorizzati in una tabella e possibilmente due stringhe, destinatario e indirizzo.Per l'indirizzo, controlla l'esistenza di "Suite" o "Apt". eccetera.e dividerlo in due valori (righe dell'indirizzo 1 e 2).

Per il destinatario, punterei e prenderei l'ultima parola di quella stringa come cognome e inserirei il resto nel campo del nome.Se non vuoi farlo, dovrai controllare il saluto (Sig., Sig.na, Dottore, ecc.) all'inizio e fare alcune ipotesi in base al numero di spazi su come è il nome costituita.

Non penso che ci sia un modo per analizzare con una precisione del 100%.

Tentativo www.indirizzo-parser.com.Usiamo il loro servizio web, che puoi testare online

Sulla base dei dati del campione:

  1. Inizierei dalla fine della stringa.Analizzare un codice postale (entrambi i formati).Leggi dalla fine al primo spazio.Se non è stato trovato alcun codice postale Errore.

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

  3. Quindi passa a Stato, utilizza nuovamente lo Spazio come delimitatore.Forse usa un elenco di ricerca per convalidare i codici di stato di 2 lettere e i nomi di stato completi.Se non viene trovato uno stato valido, errore.

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

  5. La città diventa complicata, in realtà userei una virgola qui, con il rischio di ottenere troppi dati in città.Cerca la virgola o l'inizio della riga.

  6. Se sono rimasti ancora caratteri nella stringa, inseriscili tutti in un campo indirizzo.

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

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

Tentativo:

  1. Espressione regolare per estrarre il codice postale

  2. Ricerca del codice postale (tramite DB governativo appropriato) per ottenere l'indirizzo corretto

  3. Chiedi a uno stagista di verificare manualmente che i nuovi dati corrispondano a quelli vecchi

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

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

Potresti voler dare un'occhiata a questo!! http://jgeocoder.sourceforge.net/parser.htmlHa funzionato benissimo 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 discendente ricorsivo 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 proprietà secondarie all'interno di un indirizzo come:12 1st Avenue N Suite # 2 Da qualche parte CA 12345 Stati Uniti

È 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 Regno Unito, Australia e Canada.

Ecco l'output per uno dei tuoi indirizzi di esempio.Tieni presente che la sezione del nome dovrebbe essere rimossa prima da "A.P.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947" per ridurlo a "2299 Lewes-Georgetown Hwy, Georgetown, DE 19947".Ciò si ottiene facilmente 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'

Poiché esiste la possibilità di errore nelle parole, pensa a utilizzare SOUNDEX combinato con l'algoritmo LCS per confrontare le stringhe, questo sarà di grande aiuto!

utilizzando 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 binari è disponibile una bella gemma chiamata indirizzo.Lo sto usando su uno dei miei progetti e fa il lavoro di cui ho bisogno.

L'unico problema che ho riscontrato è stato ogni volta che un indirizzo è in questo formato P. O. Box 1410 Durham, NC 27702 ha restituito zero e quindi ho dovuto sostituire "P.O.Box" con "" e successivamente è stato in grado di analizzarlo.

Esistono servizi dati che, dato un codice postale, ti forniranno un elenco dei nomi delle strade in quel codice postale.

Utilizza una regex per estrarre il codice postale o lo stato della città: trova quello corretto o, in caso di errore, ottieni entrambi.estrarre l'elenco delle strade da a fonte di dati Correggere la città e lo stato, quindi l'indirizzo.Una volta ottenuta una riga di indirizzo 1, una città, uno stato e un codice postale validi, è possibile effettuare ipotesi sulla riga di indirizzo 2..3

Non so quanto sarebbe FATTIBILE, ma non l'ho visto menzionato, quindi ho pensato di andare avanti e suggerire questo:

Se sei rigorosamente negli Stati Uniti...ottieni un enorme database di tutti i codici postali, stati, città e strade.Ora cercateli nei vostri indirizzi.Puoi convalidare ciò che trovi verificando, ad esempio, se 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 si riferisca alla via di John, ma sia il nome del destinatario...Fondamentalmente, ottieni quante più informazioni possibili e confronta i tuoi indirizzi con esse.Un esempio estremo potrebbe essere quello di ottenere UN ELENCO DI TUTTI GLI INDIRIZZI NEGLI STATI UNITI DI A e poi trovare quale ha la corrispondenza più rilevante con ciascuno dei tuoi indirizzi...

Esiste un port javascript del pacchetto perl Geo::StreetAddress::US: https://github.com/hassansin/parse-address .È basato su regex e funziona abbastanza bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top