Analyser une adresse, une ville, un état, une fermeture éclair utilisable à partir d’une chaîne

Problème: J’ai un champ d’adresse provenant d’une firebase database Access qui a été converti en Sql Server 2005. Ce champ contient tout dans un seul champ. J’ai besoin d’parsingr les différentes sections de l’adresse dans leurs champs appropriés dans un tableau normalisé. Je dois le faire pour environ 4 000 enregistrements et cela doit être reproductible.

Hypothèses:

  1. Supposons une adresse aux États-Unis (pour l’instant)

  2. supposons que la chaîne en entrée contienne parfois un destinataire (la personne à laquelle vous vous adressez) et / ou une deuxième adresse (par exemple, une suite B)

  3. les états peuvent être abrégés

  4. code postal pourrait être standard 5 chiffres ou zip + 4

  5. il y a des fautes de frappe dans certains cas

MISE À JOUR: En réponse aux questions posées, les normes n’ont pas été suivies universellement, j’ai besoin de stocker les valeurs individuelles, pas seulement les géocodes et les erreurs, les fautes de frappe (corrigées ci-dessus)

Données d’échantillon:

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

  • 11522 Shawnee Road, Greenwood DE 19950

  • 144 Kings Highway, SW Dover, DE 19901

  • Const. Intégrée Services 2 Penns Way Suite 405 New Castle, DE 19720

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

  • Nichols Excavation 2742 Pulaski Hwy Newark, DE 19711

  • 2284 route Bryn Zion, Smyrna, DE 19904

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

  • 580 North Dupont Highway Dover, DE 19901

  • PO Box 778 Dover, DE 19903

J’ai beaucoup travaillé sur ce type d’parsing. Parce qu’il y a des erreurs, vous n’obtiendrez pas une précision de 100%, mais il y a quelques petites choses que vous pouvez faire pour y arriver, puis faire un test visuel de BS. Voici la manière générale de s’y prendre. Ce n’est pas du code, parce que c’est assez académique de l’écrire, il n’y a pas d’étrangeté, juste beaucoup de manipulation de chaînes.

(Maintenant que vous avez publié des exemples de données, j’ai apporté quelques modifications mineures)

  1. Travailler en arrière Commencez par le code postal, qui sera proche de la fin, et dans l’un des deux formats connus: XXXXX ou XXXXX-XXXX. Si cela n’apparaît pas, vous pouvez supposer que vous êtes dans la partie ville, état, ci-dessous.
  2. La prochaine chose, avant le zip, sera l’état, et ce sera soit dans un format à deux lettres, soit sous la forme de mots. Vous savez ce que ce sera, il y en a seulement 50. En outre, vous pouvez combiner les mots pour aider à compenser les fautes d’orthographe.
  3. avant c’est la ville, et c’est probablement sur la même ligne que l’état. Vous pouvez utiliser une firebase database de codes postaux pour vérifier la ville et l’état en fonction du fichier zip, ou du moins l’utiliser comme détecteur de station de base.
  4. L’adresse de la rue sera généralement une ou deux lignes. La deuxième ligne sera généralement le numéro de la suite s’il y en a un, mais il pourrait également s’agir d’une boîte postale.
  5. Il sera quasiment impossible de détecter un nom sur la première ou la deuxième ligne, bien qu’il ne soit pas préfixé par un nombre (ou qu’il soit préfixé par «attn:» ou «attention à»), cela pourrait vous donner un indice comme à savoir si c’est un nom ou une ligne d’adresse.

J’espère que cela aide un peu.

Je pense que l’externalisation du problème est la meilleure solution: envoyez-la au géocodeur Google (ou Yahoo). Le géocodeur renvoie non seulement le lat / long (qui n’est pas intéressant ici), mais aussi une parsing détaillée de l’adresse, avec des champs que vous n’avez pas envoyés (y compris ZIP + 4 et comté).

Par exemple, l’parsing de “1600 Amphitheatre Parkway, Mountain View, CA” donne

{ "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] } } ] } 

Maintenant c’est analysable!

L’affiche originale a probablement évolué depuis longtemps, mais j’ai essayé de porter le module Perl Geo :: StreetAddress: US utilisé par geocoder.us sur C #, l’a jeté sur CodePlex, et je pense que trouve utile:

Analyseur d’adresse US

Sur la page d’accueil du projet, j’essaie de parler de ses limitations (très réelles). Comme il n’est pas soutenu par la firebase database USPS des adresses de rue valides, l’parsing peut être ambiguë et ne peut ni confirmer ni infirmer la validité d’une adresse donnée. Il suffit d’essayer d’extraire des données de la chaîne.

Il est destiné au cas où vous devez obtenir un dataset principalement dans les bons champs, ou souhaitez fournir un raccourci vers la saisie de données (permettant aux utilisateurs de coller une adresse dans une zone de texte plutôt que de tabuler entre plusieurs champs). Il n’est pas destiné à vérifier la délivrabilité d’une adresse.

Il ne tente pas d’parsingr quoi que ce soit au-dessus de la ligne de rue, mais on pourrait probablement se servir du regex pour obtenir quelque chose de raisonnablement proche – je le ferais probablement au numéro de la maison.

Je l’ai fait par le passé.

Soit le faire manuellement, (créer une interface graphique qui aide l’utilisateur à le faire rapidement) ou le faire automatiser et vérifier avec une firebase database d’adresses récente (vous devez l’acheter) et gérer manuellement les erreurs.

La manipulation manuelle prendra environ 10 secondes chacune, ce qui signifie que vous pouvez faire 3600/10 = 360 par heure, alors 4000 devrait vous prendre environ 11-12 heures. Cela vous donnera un taux de précision élevé.

Pour l’automatisation, vous avez besoin d’ une firebase database d’adresses récente aux États-Unis et vous devez modifier vos règles en conséquence. Je suggère de ne pas aller sur le regex (difficile à maintenir à long terme, tant d’exceptions). Optez pour une correspondance de 90% avec la firebase database, faites le rest manuellement.

Procurez-vous un exemplaire des normes d’adressage postal (USPS) à l’adresse http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf et notez qu’il ya plus de 130 pages. Regexes à mettre en œuvre ce serait fou.

Pour les adresses internationales, tous les paris sont désactivés. Les travailleurs basés aux États-Unis ne pourraient pas valider.

Vous pouvez également utiliser un service de données. Je n’ai cependant pas de recommandations.

De plus: lorsque vous envoyez les choses par la poste (c’est ce que c’est, non?) Assurez-vous de mettre “correction d’adresse demandée” sur l’enveloppe (au bon endroit) et de mettre à jour la firebase database. (Nous avons créé une interface graphique simple pour le réceptionniste, la personne qui sortinge le courrier)

Enfin, lorsque vous avez nettoyé des données, recherchez les doublons.

Je travaille dans le domaine du traitement des adresses depuis environ 5 ans et il n’y a vraiment pas de solution miracle. La solution correcte va dépendre de la valeur des données. Si ce n’est pas très précieux, lancez-le dans un parsingur, comme le suggèrent les autres réponses. Si c’est un peu précieux, vous aurez certainement besoin d’un humain pour évaluer / corriger tous les résultats de l’parsingur. Si vous recherchez une solution entièrement automatisée et reproductible, vous souhaiterez probablement parler à un fournisseur de correction d’adresse tel que Group1 ou Trillium.

Après le conseil ici, j’ai conçu la fonction suivante dans VB qui crée passable, bien que pas toujours parfait (si un nom de société et une ligne de suite sont donnés, il combine la suite et la ville) des données utilisables. S’il vous plaît n’hésitez pas à commenter / refactor / crier sur moi pour avoir enfreint une de mes propres règles, etc .:

 Public Function parseAddress(ByVal input As Ssortingng) As Collection input = input.Replace(",", "") input = input.Replace(" ", " ") Dim splitSsortingng() As Ssortingng = Split(input) Dim streetMarker() As Ssortingng = New Ssortingng() {"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 Ssortingng Dim address2 As Ssortingng = "" Dim city As Ssortingng Dim state As Ssortingng Dim zip As Ssortingng Dim streetMarkerIndex As Integer zip = splitSsortingng(splitSsortingng.Length - 1).ToSsortingng() state = splitSsortingng(splitSsortingng.Length - 2).ToSsortingng() streetMarkerIndex = getLastIndexOf(splitSsortingng, streetMarker) + 1 Dim sb As New SsortingngBuilder For counter As Integer = streetMarkerIndex To splitSsortingng.Length - 3 sb.Append(splitSsortingng(counter) + " ") Next counter city = RTrim(sb.ToSsortingng()) Dim addressIndex As Integer = 0 For counter As Integer = 0 To streetMarkerIndex If IsNumeric(splitSsortingng(counter)) _ Or splitSsortingng(counter).ToSsortingng.ToLower = "po" _ Or splitSsortingng(counter).ToSsortingng().ToLower().Replace(".", "") = "po" Then addressIndex = counter Exit For End If Next counter sb = New SsortingngBuilder For counter As Integer = addressIndex To streetMarkerIndex - 1 sb.Append(splitSsortingng(counter) + " ") Next counter address1 = RTrim(sb.ToSsortingng()) sb = New SsortingngBuilder If addressIndex = 0 Then If splitSsortingng(splitSsortingng.Length - 2).ToSsortingng() <> 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 

Le passage de la fonction parseAddress “AP Croll & Son 2299 Lewes-Georgetown Autoroute, Georgetown, DE 19947” renvoie:

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

SmartyStreets a une nouvelle fonctionnalité qui extrait les adresses de chaînes d’entrée arbitraires. (Remarque: je ne travaille pas chez SmartyStreets.)

Il a extrait avec succès toutes les adresses de l’échantillon donné dans la question ci-dessus. (Soit dit en passant, seulement 9 de ces 10 adresses sont valides.)

Voici quelques extraits: entrer la description de l'image ici

Et voici la sortie au format CSV de cette même demande:

 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,CongressionalDissortingct,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, 

J’étais le développeur qui a écrit le service à l’origine. L’algorithme que nous avons implémenté est un peu différent des réponses spécifiques ici, mais chaque adresse extraite est vérifiée par rapport à l’API de recherche d’adresse, vous pouvez donc être sûr qu’elle est valide ou non. Chaque résultat vérifié est garanti, mais nous soaps que les autres résultats ne seront pas parfaits car, comme cela a été clairement expliqué dans ce fil, les adresses sont imprévisibles, même pour les humains.

Cela ne résoudra pas votre problème, mais si vous n’aviez besoin que de données lat / long pour ces adresses, l’API Google Maps parsingra assez bien les adresses non formatées.

Bonne suggestion, vous pouvez également exécuter une requête CURL pour chaque adresse sur Google Maps et elle renverra l’adresse correctement formatée. À partir de cela, vous pouvez vous exprimer au contenu de votre coeur.

+1 sur la solution proposée par James A. Rosen car elle a bien fonctionné pour moi, cependant pour les plus complets, ce site est une lecture fascinante et la meilleure tentative de documentation d’adresses à travers le monde: http://www.columbia.edu/kermit /postal.html

Existe-t-il des normes dans la manière dont les adresses sont enregistrées? Par exemple:

  1. Existe-t-il toujours des virgules ou des lignes nouvelles séparant street1 de street2 de city of state de zip?
  2. Les adresses (route, rue, boulevard, etc.) sont-elles toujours définies? toujours abrégé? Certains de chacun?
  3. Définir “erreur”.

Ma réponse générale est une série d’expressions régulières, bien que la complexité dépende de la réponse. Et s’il n’y a pas de cohérence du tout, alors vous ne pourrez peut-être réussir que partiellement avec une expression régulière (par exemple, filtrer le code postal et l’état) et vous devrez faire le rest à la main (ou au moins soigneusement pour vous assurer de repérer les erreurs).

Une autre demande de données d’échantillons.

Comme cela a été mentionné, je travaillerais à reculons à partir du zip.

Une fois que vous avez un fichier zip, je recherche une firebase database zip, stocke les résultats et les supprime ainsi que le fichier zip de la chaîne.

Cela vous laissera avec le gâchis d’adresse. Les adresses MOST (All?) Commenceront par un nombre. Recherchez donc la première occurrence d’un nombre dans la chaîne restante et récupérez-en tout à la (nouvelle) fin de la chaîne. Ce sera votre adresse. Tout ce qui se trouve à gauche de ce numéro est probablement un destinataire.

Vous devriez maintenant avoir la ville, l’état et le code postal stockés dans une table et éventuellement deux chaînes, un destinataire et une adresse. Pour l’adresse, vérifiez l’existence de “Suite” ou “Apt”. etc. et divisé en deux valeurs (lignes d’adresse 1 et 2).

Pour le destinataire, je tapotais et attrapais le dernier mot de cette chaîne comme nom de famille et mettais le rest dans le champ du prénom. Si vous ne voulez pas faire cela, vous devrez vérifier les salutations (M., Mme, Dr., etc.) au début et faire des hypothèses en fonction du nombre d’espaces pour déterminer le nom. composé.

Je ne pense pas que vous puissiez parsingr avec une précision de 100%.

Essayez http://www.address-parser.com . Nous utilisons leur service Web, que vous pouvez tester en ligne

Basé sur les données de l’échantillon:

  1. Je commencerais à la fin de la chaîne. Analyser un code postal (quel que soit le format). Lire fin au premier espace. Si aucun code postal n’a été trouvé, erreur.

  2. Couper la fin pour les espaces et les caractères spéciaux (virgules)

  3. Puis passez à l’état, utilisez à nouveau l’espace comme délimiteur. Peut-être utiliser une liste de recherche pour valider les codes d’état à 2 lettres et les noms d’état complets. Si aucun état valide n’a été trouvé, erreur.

  4. Coupez à nouveau les espaces et les virgules à partir de la fin.

  5. La ville devient délicate, j’utiliserais une virgule ici, au risque de recevoir trop de données en ville. Recherchez la virgule ou le début de la ligne.

  6. Si vous avez toujours des caractères dans la chaîne, insérez tout cela dans un champ d’adresse.

Ce n’est pas parfait, mais ça devrait être un bon sharepoint départ.

S’il s’agit de données entrées par l’utilisateur, vous passerez trop de temps à essayer de coder autour des exceptions.

Essayer:

  1. Expression régulière pour extraire le code postal

  2. Recherche de code postal (via la firebase database gouvernementale appropriée) pour obtenir la bonne adresse

  3. Demandez à un stagiaire de vérifier manuellement que les nouvelles données correspondent à l’ancienne

Cela ne résoudra pas votre problème, mais si vous n’aviez besoin que de données lat / long pour ces adresses, l’API Google Maps parsingra assez bien les adresses non formatées.

RecogniContact est un object Windows COM qui parsing les adresses américaines et européennes. Vous pouvez l’essayer directement sur http://www.loquisoft.com/index.php?page=8

Vous voudrez peut-être vérifier cela! http://jgeocoder.sourceforge.net/parser.html Travaillé comme un charme pour moi.

Ce type de problème est difficile à résoudre en raison des ambiguïtés sous-jacentes des données.

Voici une solution basée sur Perl qui définit un arbre de grammaire de descente récursif basé sur des expressions régulières pour parsingr de nombreuses combinaisons d’adresses de rue valides: http://search.cpan.org/~kimryan/Lingua-EN-AddressParse-1.20/lib/Lingua /FR/AddParse.pm . Cela inclut les sous-propriétés dans une adresse telle que: 12 1st Avenue N Suite # 2 Somewhere CA 12345 USA

Il est similaire à http://search.cpan.org/~timb/Geo-StreetAddress-US-1.03/US.pm mentionné ci-dessus, mais fonctionne également pour les adresses qui ne sont pas des États-Unis, tels que le Royaume-Uni, l’Australie et Canada.

Voici la sortie de l’une de vos adresses exemples. Notez que la section du nom devrait être enlevée en premier de “AP Croll & Son 2299, Lewes-Georgetown Hwy, Georgetown, DE 19947” pour la réduire à “2299 Lewes-Georgetown Hwy, Georgetown, DE 19947”. Cela se fait facilement en supprimant toutes les données jusqu’au premier numéro trouvé dans la chaîne.

 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' 

Comme il y a des risques d’erreur dans les mots, pensez à utiliser SOUNDEX en combinaison avec l’algorithme LCS pour comparer les chaînes, cela aidera beaucoup!

en utilisant Google API

 $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); 

Pour les développeurs Ruby ou Rails, il existe un joli bijou appelé street_address . Je l’ai utilisé sur un de mes projets et il fait le travail dont j’ai besoin.

Le seul problème que je rencontrais était à chaque fois qu’une adresse se trouvait dans ce format: PO Box 1410 Durham, NC 27702 elle était nulle et par conséquent, je devais remplacer “Boîte postale” par “et après cela, elle était capable de l’parsingr”.

Il existe des services de données qui, avec un code postal, vous donneront la liste des noms de rue dans ce code postal.

Utilisez une regex pour extraire Zip ou City State – trouvez la bonne ou si une erreur vous parvient. extrayez la liste des rues d’une source de données Corrigez la ville et l’état, puis l’adresse de la rue. Une fois que vous obtenez une adresse valide, la ligne 1, la ville, l’état et le code postal, vous pouvez alors faire des suppositions sur la ligne d’adresse 2..3

Je ne sais pas ce que cela serait FAISIBLE, mais je n’ai pas vu cela mentionné alors j’ai pensé aller de l’avant et suggérer ceci:

Si vous êtes ssortingctement aux États-Unis … obtenez une énorme firebase database contenant tous les codes postaux, États, villes et rues. Maintenant, cherchez-les dans vos adresses. Vous pouvez valider ce que vous trouvez en testant, par exemple, la ville que vous avez trouvée dans l’état que vous avez trouvé ou en vérifiant si la rue que vous avez trouvée existe dans la ville que vous avez trouvée. Sinon, il y a de fortes chances pour que John ne soit pas pour John’s Street, mais le nom du destinataire … Fondamentalement, obtenez le plus d’informations possible et vérifiez votre adresse. Un exemple extrême serait d’obtenir une liste de toutes les adresses aux États-Unis et de trouver celle qui correspond le mieux à chacune de vos adresses …

Il existe un port javascript de perl Package Geo :: StreetAddress :: US: https://github.com/hassansin/parse-address . C’est basé sur les regex et fonctionne assez bien.