Comment analyser libre de rue/adresse postale du texte, et dans les composants

nous faisons des affaires en grande partie aux États-Unis et essayons d'améliorer l'expérience des utilisateurs en combinant tous les champs d'adresse dans un seul secteur de texte. Mais il y a quelques problèmes:

  • l'adresse des types d'utilisateurs peut ne pas être correcte ou dans un format standard
  • l'adresse doit être séparée en parties (rue, ville, État, etc.) pour traiter les paiements par carte de crédit
  • les utilisateurs peuvent entrer plus que adresse (comme leur nom ou société avec elle)
  • Google peut le faire, mais les conditions de service et les limites de requête sont prohibitives, en particulier sur un budget serré

apparemment, c'est une question courante:

  • script PHP pour analyser l'adresse?
  • Comment puis-je analyser l'adresse en format libre pour enregistrer dans la base de données
  • java à l'adresse postale de l'analyseur
  • méthode plus efficace pour extraire les composants d'adresse
  • Comment puis-je afficher une adresse postale pré-remplie dans l'écran contacts avec Rue, Ville, zip sur android
  • PHP regexp NOUS adresse

Est-il un moyen d'isoler une adresse à partir du texte autour d'elle et de pause en morceaux? Est-il une expression régulière pour analyser les adresses?

105
demandé sur Community 2012-06-22 20:19:47

7 réponses

j'ai beaucoup vu cette question lorsque j'ai travaillé pour une entreprise de vérification d'adresse. Je poste la réponse ici pour la rendre plus accessible aux programmeurs qui cherchent autour de la même question. La société, j'étais au transformés milliards d'adresses, et nous avons beaucoup appris dans le processus.

tout d'abord, nous devons comprendre quelques choses au sujet des adresses.

les adresses ne sont pas régulier 151990920"

This signifie que les expressions régulières sont. J'ai tout vu, de simples expressions régulières qui correspondent à des adresses dans un format très spécifique, à ceci:

/\S+(\d{2,5}\s+) (?![a / p]m\b) ([A-zA-Z|\s+]{1,5}){1,2})?([\s/\,/.]+)?(([a-zA-Z|\s+]{1,30}){1,4})(cour|ct|rue|st|lecteur|dr|lane|ln|route|rd|blvd)([\s|\,|./ \;]+)?(([a-zA-Z|\s+]{1,30}){1,2})([\s/\,/.]+)?\b(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|GU|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NC|ND|NE|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VI|VT|WA|WI|WV|WY)([\s|\,|.]+)?(\S+\D{5})?([\s/\,/.]+) / i

... à ce où un 900+ le fichier line-class génère une expression régulière supermassive à la volée pour correspondre encore plus. Je ne les recommande pas (par exemple, voici un violon du regex ci-dessus, qui fait beaucoup d'erreurs ). Il n'y a pas de formule magique facile pour que ça marche. En théorie et par théorie, il n'est pas possible de faire correspondre les adresses avec une expression régulière.

USPS Publication 28 documente les différents formats des adresses qui sont possibles, avec tous leurs mots-clés et les variatons. Pire encore, les adresses sont souvent ambiguës. Les mots peuvent signifier plus d'une chose ("St "peut être" Saint "ou" rue") et il y a des mots que je suis presque sûr qu'ils ont inventé. (Qui savait que "Stravenue" était un suffixe de rue?)

vous auriez besoin d'un code qui comprenne vraiment les adresses, et si ce code existe, c'est un secret commercial. Mais vous pourriez probablement rouler votre propre si vous êtes vraiment en que.

les Adresses viennent dans des formes inattendues et tailles

voici quelques adresses truquées (mais complètes):

1)  102 main street
    Anytown, state

2)  400n 600e #2, 52173

3)  p.o. #104 60203

même ceux-ci sont peut-être valables:

4)  829 LKSDFJlkjsdflkjsdljf Bkpw 12345

5)  205 1105 14 90210

évidemment, ceux-ci ne sont pas standardisés. La ponctuation et les sauts de ligne ne sont pas garantis. Voilà ce qui se passe:

  1. numéro 1 est complet parce qu'il contient un adresse de la rue d'une ville et l'état. Avec cette information, il y a suffisamment d'identification de l'adresse, et elle peut être considérée comme "livrable" (avec une certaine standardisation).

  2. numéro 2 est complet parce qu'il contient également une adresse municipale (avec numéro secondaire/unité) et un code postal à 5 chiffres, ce qui est suffisant pour identifier une adresse.

  3. Numéro 3 est un remplir le format de la boîte postale, car il contient un code postal.

  4. numéro 4 est aussi complet parce que le code postal est unique , ce qui signifie qu'une entité privée ou une société a acheté cet espace d'adresse. Un code ZIP unique est pour les volumes élevés ou les espaces de livraison concentrés. Tout ce qui est adressé au Code Postal 12345 va à General Electric à Schenectady, NY. Cet exemple ne touchera personne particulier, mais L'USPS serait encore en mesure de le livrer.

  5. Numéro 5 est également complète, croyez-le ou pas. Avec seulement ces nombres, l'adresse complète peut être découverte lorsqu'on la compare à une base de données de toutes les adresses possibles. Remplir les directives manquantes, l'indicateur secondaire et le code ZIP+4 est trivial quand vous voyez chaque nombre comme un composant. Voici à quoi il ressemble, entièrement développé et standardisé:

205 N 1105 W Apt 14

Beverly Hills CA 90210-5221

données d'Adresse n'est pas votre propre

dans la plupart des pays qui fournissent des données d'adresse officielles aux fournisseurs agréés, les données d'adresse elles-mêmes appartiennent à l'organisme directeur. Aux États-Unis, L'USPS possède les adresses. Il en va de même pour Postes Canada, Royal Mail et d'autres, bien que chaque pays applique ou définit la propriété un peu différemment. Savoir cela est important, car il interdit habituellement l'ingénierie inverse de la base de données d'adresses. Vous devez être prudent sur la manière d'acquérir, stocker et utiliser les données.

Google Maps est un go-to commun pour les corrections d'adresses rapides, mais le TOS est plutôt prohibitif; par exemple, vous ne pouvez pas utiliser leurs données ou APIs sans montrer une carte Google, et à des fins non-commerciales seulement (sauf si vous payez), et vous ne pouvez pas stocker les données (sauf pour la mise en cache temporaire). Du sens. Les données de Google sont parmi les meilleures au monde. Cependant, Google Maps ne pas vérifier l'adresse. Si une adresse n'existe pas, elle vous indiquera quand même où l'adresse serait si elle existait (essayez-la dans votre propre rue; utilisez un numéro de maison dont vous savez qu'il n'existe pas). C'est parfois utile, mais soyez conscient de cela.

La Politique d'utilisation de Nominatim, , est tout aussi restrictive, surtout pour les volumes élevés et l'utilisation commerciale, et les données sont principalement tirées de sources libres, de sorte qu'elle n'est pas aussi bien entretenue (telle est la nature des projets ouverts) -- cependant, cela peut toujours convenir à vos besoins. Elle est soutenue par une grande communauté.

L'USPS lui-même a une API, mais il descend beaucoup et est livré sans garanties ni support. Il pourrait également être difficile à utiliser. Certaines personnes l'utilisent avec parcimonie, sans aucun problème. Mais il est facile de ne pas remarquer que L'USPS exige que vous utilisiez son API uniquement pour confirmer les adresses à expédier à travers eux.

les Gens attendent d'adresses dur

Malheureusement, nous avons conditionné notre société à s'attendre à ce que les adresses soient compliquées. Il y a des douzaines de bons articles UX partout sur Internet à ce sujet, mais le fait est que, si vous avez un formulaire d'adresse avec des champs individuels, c'est ce que les utilisateurs expect, même si cela rend plus difficile pour edge-case adresses qui ne correspondent pas au format que le formulaire attend, ou peut-être le formulaire nécessite un champ qu'il ne devrait pas. Ou les utilisateurs ne savent pas où mettre une certaine partie de leur adresse.

je pourrais continuer encore et encore sur le mauvais UX des formulaires de paiement ces jours-ci, mais à la place je vais juste dire que la combinaison des adresses dans un seul champ sera un bienvenue changement -- les gens seront en mesure de taper leur adresse Comment ils voient juste, plutôt que d'essayer de comprendre votre formulaire long. Cependant, ce changement sera inattendu et les utilisateurs peuvent le trouver un peu déconcertant au début. Sois juste conscient de ça.

une partie de cette douleur peut être atténuée en mettant le champ du pays devant l'adresse. Lorsque vous remplissez le champ pays d'abord, vous savez comment faire de votre formulaire apparaît. Peut-être que vous avez une bonne façon de traiter avec les adresses américaines à champ unique, alors s'ils choisissent États-Unis, vous pouvez réduire votre formulaire à un seul champ, sinon afficher les champs composants. Juste des choses auxquelles penser!

maintenant nous savons pourquoi c'est difficile; que pouvez-vous faire à ce sujet?

l'USPS autorise les vendeurs par un processus appelé Certification CASS™ pour fournir des adresses vérifiées aux clients. Ces fournisseurs ont accès à la base de données de L'USPS, mise à jour mensuellement. Leur logiciel doit être conforme à des normes rigoureuses pour être certifié, et ils ne sont pas souvent exiger l'acceptation des conditions limitatives mentionnées ci-dessus.

il existe de nombreuses entreprises certifiées CASS qui peuvent traiter des listes ou avoir des API: Melissa Data, Experian QAS, et SmartyStreets pour n'en nommer que quelques-unes.

(en raison d'obtenir flak pour" publicité " j'ai tronqué ma réponse à ce point. C'est à vous de trouver une solution qui fonctionne pour vous.)

La Vérité: Vraiment, les gens, j' ne travaille dans aucune de ces entreprises. Il n'est pas une publicité.

234
répondu Matt 2015-07-02 01:16:42

il y a beaucoup de vendeurs d'adresses de rue. Ils viennent en deux saveurs de base - ceux qui ont des bases de données de noms de lieux et de noms de rue, et ceux qui ne le font pas.

un analyseur d'adresse de rue d'expression régulière peut obtenir jusqu'à environ 95% de succès sans beaucoup de problèmes. Puis vous commencez à frapper les cas inhabituels. Le Perl dans CPAN, "Geo:: StreetAddress:: US", est à peu près ce bon. Il y a des ports Python et Javascript pour cela, tous open source. J'ai une meilleure version en Python qui augmente légèrement le taux de succès en traitant plus de cas. Pour obtenir les derniers 3% droite, cependant, vous avez besoin de bases de données pour aider à la désambiguïsation.

une base de données avec des codes ZIP à trois chiffres et des noms et abréviations d'États américains est d'une grande aide. Lorsqu'un analyseur voit un code postal et un nom d'état cohérents, il peut commencer à se verrouiller sur le format. Cela fonctionne très bien pour les États-Unis et le Royaume-Uni.

adresse de la rue appropriée fin et fonctionne à l'envers. C'est comme ça que les systèmes USPS le font. Les adresses sont moins ambiguës à la fin, où les noms de pays, les noms de ville et les codes postaux sont relativement faciles à reconnaître. Les noms de rue peuvent généralement être isolé. Les emplacements sur les rues sont les plus complexes à analyser; là, vous rencontrez des choses comme "cinquième étage" et"Staples Pavillion". C'est quand une base de données est une grande aide.

10
répondu John Nagle 2015-04-05 05:25:59

libpostal: une bibliothèque open-source pour analyser les adresses, la formation avec des données de OpenStreetMap, OpenAddresses et OpenCage.

https://github.com/openvenues/libpostal ( plus d'informations sur ce )

autres outils/ services:

10
répondu David Portabella 2017-07-11 08:34:28

mise à jour: Geocode.xyz travaille maintenant dans le monde entier. Pour des exemples voir https://geocode.xyz

pour les États-Unis, le Mexique et le Canada, Voir géocodeur.ca .

par exemple:

Entrée: quelque chose qui se passe près de l'intersection des rues main et arthur kill rd new york

sortie:

<geodata>
  <latt>40.5123510000</latt>
  <longt>-74.2500500000</longt>
  <AreaCode>347,718</AreaCode>
  <TimeZone>America/New_York</TimeZone>
  <standard>
    <street1>main</street1>
    <street2>arthur kill</street2>
    <stnumber/>
    <staddress/>
    <city>STATEN ISLAND</city>
    <prov>NY</prov>
    <postal>11385</postal>
    <confidence>0.9</confidence>
  </standard>
</geodata>

vous pouvez également vérifier les résultats dans l'interface web ou obtenir la sortie comme Json ou Jsonp. par exemple. je cherche des restaurants autour de 123 Main Street, New York

8
répondu Ervin Ruci 2018-04-25 20:29:36

pas de code? Pour la honte!

voici un analyseur D'adresse JavaScript simple. Il est assez terrible pour chaque raison simple que Matt donne dans sa thèse ci - dessus (dont je suis presque 100% d'accord avec: les adresses sont des types complexes, et les humains font des erreurs; mieux de externaliser et d'automatiser cela-quand vous pouvez vous le permettre).

Mais plutôt que de pleurer, j'ai décidé d'essayer:

ce code fonctionne bien pour analyser la plupart des résultats Esri pour findAddressCandidate et aussi avec d'autres géocodeurs (inverses)qui renvoient des adresses de ligne individuelle où la rue/ville/État sont délimitées par des guillemets. Vous pouvez étendre si vous voulez ou écrire des parsers spécifiques au pays. Ou utilisez simplement ceci comme étude de cas de la façon dont l'exercice peut être difficile ou à quel point je suis nul à JavaScript. J'admets que je n'ai passé qu'une trentaine de minutes là-dessus (les itérations futures pourraient ajouter des caches, la validation zip, et l'état des recherches ainsi que le contexte de localisation de l'utilisateur), mais cela a fonctionné pour mon cas d'utilisation: fin l'utilisateur voit la forme qui analyse la réponse de recherche de géocode dans 4 boîtes de texte. Si le parsing d'adresse sort mal (ce qui est rare à moins que les données source étaient pauvres) ce n'est pas une grosse affaire - l'utilisateur obtient de vérifier et de corriger! (Mais pour les solutions automatisées pourrait soit rejeter/ignorer ou Signaler comme erreur afin que dev puisse prendre en charge le nouveau format ou corriger les données source.)

/* 
address assumptions:
- US addresses only (probably want separate parser for different countries)
- No country code expected.
- if last token is a number it is probably a postal code
-- 5 digit number means more likely
- if last token is a hyphenated string it might be a postal code
-- if both sides are numeric, and in form #####-#### it is more likely
- if city is supplied, state will also be supplied (city names not unique)
- zip/postal code may be omitted even if has city & state
- state may be two-char code or may be full state name.
- commas: 
-- last comma is usually city/state separator
-- second-to-last comma is possibly street/city separator
-- other commas are building-specific stuff that I don't care about right now.
- token count:
-- because units, street names, and city names may contain spaces token count highly variable.
-- simplest address has at least two tokens: 714 OAK
-- common simple address has at least four tokens: 714 S OAK ST
-- common full (mailing) address has at least 5-7:
--- 714 OAK, RUMTOWN, VA 59201
--- 714 S OAK ST, RUMTOWN, VA 59201
-- complex address may have a dozen or more:
--- MAGICICIAN SUPPLY, LLC, UNIT 213A, MAGIC TOWN MALL, 13 MAGIC CIRCLE DRIVE, LAND OF MAGIC, MA 73122-3412
*/

var rawtext = $("textarea").val();
var rawlist = rawtext.split("\n");

function ParseAddressEsri(singleLineaddressString) {
  var address = {
    street: "",
    city: "",
    state: "",
    postalCode: ""
  };

  // tokenize by space (retain commas in tokens)
  var tokens = singleLineaddressString.split(/[\s]+/);
  var tokenCount = tokens.length;
  var lastToken = tokens.pop();
  if (
    // if numeric assume postal code (ignore length, for now)
    !isNaN(lastToken) ||
    // if hyphenated assume long zip code, ignore whether numeric, for now
    lastToken.split("-").length - 1 === 1) {
    address.postalCode = lastToken;
    lastToken = tokens.pop();
  }

  if (lastToken && isNaN(lastToken)) {
    if (address.postalCode.length && lastToken.length === 2) {
      // assume state/province code ONLY if had postal code
      // otherwise it could be a simple address like "714 S OAK ST"
      // where "ST" for "street" looks like two-letter state code
      // possibly this could be resolved with registry of known state codes, but meh. (and may collide anyway)
      address.state = lastToken;
      lastToken = tokens.pop();
    }
    if (address.state.length === 0) {
      // check for special case: might have State name instead of State Code.
      var stateNameParts = [lastToken.endsWith(",") ? lastToken.substring(0, lastToken.length - 1) : lastToken];

      // check remaining tokens from right-to-left for the first comma
      while (2 + 2 != 5) {
        lastToken = tokens.pop();
        if (!lastToken) break;
        else if (lastToken.endsWith(",")) {
          // found separator, ignore stuff on left side
          tokens.push(lastToken); // put it back
          break;
        } else {
          stateNameParts.unshift(lastToken);
        }
      }
      address.state = stateNameParts.join(' ');
      lastToken = tokens.pop();
    }
  }

  if (lastToken) {
    // here is where it gets trickier:
    if (address.state.length) {
      // if there is a state, then assume there is also a city and street.
      // PROBLEM: city may be multiple words (spaces)
      // but we can pretty safely assume next-from-last token is at least PART of the city name
      // most cities are single-name. It would be very helpful if we knew more context, like
      // the name of the city user is in. But ignore that for now.
      // ideally would have zip code service or lookup to give city name for the zip code.
      var cityNameParts = [lastToken.endsWith(",") ? lastToken.substring(0, lastToken.length - 1) : lastToken];

      // assumption / RULE: street and city must have comma delimiter
      // addresses that do not follow this rule will be wrong only if city has space
      // but don't care because Esri formats put comma before City
      var streetNameParts = [];

      // check remaining tokens from right-to-left for the first comma
      while (2 + 2 != 5) {
        lastToken = tokens.pop();
        if (!lastToken) break;
        else if (lastToken.endsWith(",")) {
          // found end of street address (may include building, etc. - don't care right now)
          // add token back to end, but remove trailing comma (it did its job)
          tokens.push(lastToken.endsWith(",") ? lastToken.substring(0, lastToken.length - 1) : lastToken);
          streetNameParts = tokens;
          break;
        } else {
          cityNameParts.unshift(lastToken);
        }
      }
      address.city = cityNameParts.join(' ');
      address.street = streetNameParts.join(' ');
    } else {
      // if there is NO state, then assume there is NO city also, just street! (easy)
      // reasoning: city names are not very original (Portland, OR and Portland, ME) so if user wants city they need to store state also (but if you are only ever in Portlan, OR, you don't care about city/state)
      // put last token back in list, then rejoin on space
      tokens.push(lastToken);
      address.street = tokens.join(' ');
    }
  }
  // when parsing right-to-left hard to know if street only vs street + city/state
  // hack fix for now is to shift stuff around.
  // assumption/requirement: will always have at least street part; you will never just get "city, state"  
  // could possibly tweak this with options or more intelligent parsing&sniffing
  if (!address.city && address.state) {
    address.city = address.state;
    address.state = '';
  }
  if (!address.street) {
    address.street = address.city;
    address.city = '';
  }

  return address;
}

// get list of objects with discrete address properties
var addresses = rawlist
  .filter(function(o) {
    return o.length > 0
  })
  .map(ParseAddressEsri);
$("#output").text(JSON.stringify(addresses));
console.log(addresses);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea>
27488 Stanford Ave, Bowden, North Dakota
380 New York St, Redlands, CA 92373
13212 E SPRAGUE AVE, FAIR VALLEY, MD 99201
1005 N Gravenstein Highway, Sebastopol CA 95472
A. P. Croll &amp; Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947
11522 Shawnee Road, Greenwood, DE 19950
144 Kings Highway, S.W. Dover, DE 19901
Intergrated Const. 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 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
P.O. Box 778, Dover, DE 19903
714 S OAK ST
714 S OAK ST, RUM TOWN, VA, 99201
3142 E SPRAGUE AVE, WHISKEY VALLEY, WA 99281
27488 Stanford Ave, Bowden, North Dakota
380 New York St, Redlands, CA 92373
</textarea>
<div id="output">
</div>
1
répondu nothingisnecessary 2018-03-15 19:05:08

Dans notre projet, nous avons utilisé l'adresse suivante analyseur. Il analyser adresses pour la plupart des pays dans le monde avec une bonne précision.

http://address-parser.net /

il est disponible comme bibliothèque autonome ou comme API live.

0
répondu Waqas Anwar 2017-03-16 11:40:37

si vous voulez vous fier aux données OSM libpostal est très puissant et traite beaucoup des mises en garde les plus courantes avec les entrées d'adresse.

0
répondu Vitor Magalhães 2017-07-28 13:22:09