Анализировать пригодный для использования уличный адрес, город, штат, почтовый индекс из строки [закрыто]

StackOverflow https://stackoverflow.com/questions/16413

Вопрос

Проблема:У меня есть поле адреса из базы данных Access, которое было преобразовано в Sql Server 2005.В этом поле есть все в одном поле.Мне нужно разобрать отдельные разделы адреса на соответствующие поля в нормализованной таблице.Мне нужно сделать это примерно для 4000 записей, и это должно быть повторяемым.

Предположения:

  1. Предположим, что адрес находится в США (на данный момент)

  2. предположим, что входная строка иногда будет содержать адресата (человека, к которому обращаются) и/или второй почтовый адрес (т. е.Люкс Б)

  3. штаты могут быть сокращены

  4. почтовый индекс может быть стандартным 5-значным или zip+4.

  5. в некоторых случаях есть опечатки

ОБНОВЛЯТЬ:Отвечая на заданные вопросы, стандарты не соблюдались повсеместно, мне нужно хранить отдельные значения, а не только геокодирование, и ошибки означают опечатку (исправлено выше).

Образец данных:

  • А.П.Croll & Son 2299 Льюис-Джорджтаун шоссе, Джорджтаун, Делавэр, 19947

  • 11522 Шони Роуд, Гринвуд, DE 19950

  • 144 Kings Highway, ЮЗ.Дувр, DE 19901

  • Интегрированная Конст.Услуги 2 Penns Way Suite 405 New Castle, DE 19720

  • Humes Realty 33 Bridle Ridge Court, Льюис, DE 19958

  • Раскопки Николса, 2742 Pulaski Hwy, Ньюарк, Делавэр, 19711.

  • 2284 Bryn Zion Road, Смирна, DE 19904

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

  • 580 North Dupont Highway, Дувр, DE 19901

  • П.О.Box 778 Дувр, DE 19903

Это было полезно?

Решение

Я проделал большую работу по такому анализу.Поскольку есть ошибки, вы не получите 100% точности, но есть несколько вещей, которые вы можете сделать, чтобы пройти большую часть пути, а затем провести визуальный тест BS.Вот общий способ сделать это.Это не код, потому что его писать довольно академично, в нем нет ничего странного, просто много обработки строк.

(Теперь, когда вы опубликовали примеры данных, я внес некоторые незначительные изменения)

  1. Работайте в обратном направлении.Начните с почтового индекса, который будет ближе к концу и в одном из двух известных форматов:ХХХХ или ХХХХ-ХХХХ.Если этого не появляется, вы можете предположить, что находитесь в городе, части штата, указанной ниже.
  2. Следующее, перед zip, будет состояние, и оно будет либо в двухбуквенном формате, либо в виде слов.Вы тоже знаете, какие это будут — их всего 50.Кроме того, вы можете озвучить слова, чтобы компенсировать орфографические ошибки.
  3. перед этим есть город, и это вероятно на одной линии с государством.Вы можете использовать база данных почтовых индексов проверить город и штат по zip или хотя бы использовать как детектор БС.
  4. Уличный адрес обычно состоит из одной или двух строк.Вторая строка обычно представляет собой номер пакета, если он есть, но это также может быть почтовый ящик.
  5. Обнаружить имя в первой или второй строке будет почти невозможно, хотя, если перед ним не стоит цифра (или если перед ним стоит префикс «attn:» или «внимание:», это может дать вам подсказку, как будь то имя или адресная строка.

Надеюсь, это чем-то поможет.

Другие советы

Я считаю, что лучше всего передать эту проблему на аутсорсинг:отправьте его в геокодер Google (или Yahoo).Геокодер возвращает не только широту/долготу (которые здесь не представляют интереса), но и подробный анализ адреса с заполненными полями, которые вы не отправляли (включая ZIP+4 и округ).

Например, анализ «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]
      }
    }
  ]
}

Сейчас это разборчиво!

Оригинальный постер, вероятно, уже давно вышел в свет, но я попробовал портировать Perl. Гео::StreetAddress:US модуль, используемый geocoder.us на C#, выложил его на CodePlex и думаю, что люди, столкнувшиеся с этим вопросом в будущем, могут найти это полезным:

Парсер адресов США

На домашней странице проекта я пытаюсь рассказать о его (вполне реальных) ограничениях.Поскольку он не поддерживается базой данных действительных почтовых адресов USPS, синтаксический анализ может быть неоднозначным и не может ни подтвердить, ни опровергнуть достоверность данного адреса.Он может просто попытаться извлечь данные из строки.

Он предназначен для случаев, когда вам нужно получить набор данных в основном в нужных полях или вы хотите предоставить ярлык для ввода данных (позволяя пользователям вставлять адрес в текстовое поле, а не переключаться между несколькими полями с помощью табуляции).Это нет предназначен для проверки доставляемости адреса.

Он не пытается проанализировать что-либо выше линии улицы, но, вероятно, можно было бы возиться с регулярным выражением, чтобы получить что-то достаточно близкое - я бы, вероятно, просто прервал его на номере дома.

Я делал это в прошлом.

Либо сделайте это вручную (создайте хороший графический интерфейс, который поможет пользователю сделать это быстро), либо автоматизируйте его и проверьте последнюю базу данных адресов (вам придется ее купить) и вручную обработайте ошибки.

Ручная обработка займет около 10 секунд каждое, то есть вы можете сделать 3600/10 = 360 в час, поэтому 4000 займут у вас примерно 11-12 часов.Это обеспечит вам высокую точность.

Для автоматизации вы нуждаться недавнюю базу данных адресов в США и скорректируйте свои правила с учетом этого.Я предлагаю не увлекаться регулярным выражением (трудно поддерживать его в долгосрочной перспективе, так много исключений).Обеспечьте совпадение 90% с базой данных, остальное сделайте вручную.

Получите копию Стандартов почтовой адресации (USPS) по адресу: http://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf и обратите внимание, что его длина составляет более 130 страниц.Регулярные выражения для реализации этого были бы сумасшедшими.

Для международных адресов все ставки отключены.Работники из США не смогут подтвердить это.

Альтернативно, используйте службу передачи данных.Однако у меня нет никаких рекомендаций.

Более того:когда вы отправляете материалы по почте (для этого они и нужны, верно?), убедитесь, что вы поместили на конверте «требуется исправление адреса» (в нужном месте) и обновлять база данных.(Мы сделали простой графический интерфейс для сотрудника стойки регистрации;человек, который на самом деле сортирует почту)

Наконец, когда вы очистите данные, найдите дубликаты.

После совета здесь я разработал следующую функцию в VB, которая создает сносные, хотя и не всегда идеальные (если указаны название компании и строка набора, она объединяет набор и город) полезные данные.Пожалуйста, не стесняйтесь комментировать/рефакторить/кричать на меня за нарушение одного из моих собственных правил и т. д.:

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

Прохождение parseAddress функция «А.П.Croll & Son 2299 Lewes-Georgetown Hwy, Джорджтаун, DE 19947» возвращается:

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

Я работаю в области обработки адресов уже около 5 лет, и серебряной пули на самом деле не существует.Правильное решение будет зависеть от значения данных.Если это не очень ценно, пропустите его через парсер, как предлагают другие ответы.Если это хоть сколько-нибудь ценно, вам обязательно понадобится человек, который оценит/исправит все результаты парсера.Если вы ищете полностью автоматизированное, воспроизводимое решение, вам, вероятно, стоит поговорить с поставщиком исправлений адресов, например Group1 или Trillium.

В SmartyStreets появилась новая функция, которая извлекает адреса из произвольных входных строк.(Примечание:Я не работаю в SmartyStreets.)

Он успешно извлек все адреса из образца входных данных, приведенного в вопросе выше.(Кстати, только 9 из этих 10 адресов действительны.)

Вот некоторые результаты:enter image description here

А вот результат того же запроса в формате CSV:

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,

Я был разработчиком, который изначально написал этот сервис.Алгоритм, который мы реализовали, немного отличается от любых конкретных ответов здесь, но каждый извлеченный адрес проверяется с помощью API поиска адреса, поэтому вы можете быть уверены, действителен он или нет.Каждый проверенный результат гарантирован, но мы знаем, что другие результаты не будут идеальными, потому что, как было сделано совершенно ясно в этой теме адреса непредсказуемы, иногда даже для людей.

Это не решит вашу проблему, но если вам нужны только данные LAT/Long для этих адресов, API Google Maps довольно хорошо проанализирует неформатированные адреса.

Хорошее предложение. В качестве альтернативы вы можете выполнить запрос CURL для каждого адреса на Картах Google, и он вернет адрес в правильном формате.Исходя из этого, вы можете выполнять регулярные выражения в свое удовольствие.

+1 к Джеймсу А.Решение, предложенное Розеном, помогло мне, однако для любителей этот сайт представляет собой увлекательное чтение и лучшую попытку, которую я видел в документировании адресов по всему миру: http://www.columbia.edu/kermit/postal.html

Существуют ли вообще какие-либо стандарты в способе записи адресов?Например:

  1. Всегда ли есть запятые или новые строки, отделяющие улицу 1 от улицы 2, город, штат и почтовый индекс?
  2. Всегда ли прописываются типы адресов (дорога, улица, бульвар и т. д.)?всегда сокращенно?Некоторые из каждого?
  3. Дайте определение понятию «ошибка».

Мой общий ответ — это серия регулярных выражений, хотя сложность зависит от ответа.А если согласованности нет вообще, то с помощью Regex вы сможете добиться лишь частичного успеха (т.е.:фильтрация почтового индекса и штата), а все остальное придется делать вручную (или, по крайней мере, очень внимательно проверять все остальное, чтобы убедиться, что вы заметили ошибки).

Еще один запрос примеров данных.

Как уже упоминалось, я буду работать в обратном направлении от молнии.

Если у вас есть zip-архив, я запросил бы базу данных zip-файлов, сохранил результаты и удалил их и zip-архив из строки.

Это оставит вас в беспорядке с адресами.БОЛЬШИНСТВО (Все?) адресов начинаются с цифры, поэтому найдите первое вхождение числа в оставшейся строке и захватите все от него до (нового) конца строки.Это будет ваш адрес.Все, что находится слева от этого числа, скорее всего, является адресатом.

Теперь у вас должны быть сохранены город, штат и почтовый индекс в таблице и, возможно, две строки: адресат и адрес.Для адреса проверьте наличие «Suite» или «Apt». и т. д.и разделите его на два значения (адресные строки 1 и 2).

Для адресата я бы взял последнее слово этой строки в качестве фамилии, а остальное поместил в поле имени.Если вы не хотите этого делать, вам нужно будет проверить приветствие (мистер, госпожа, доктор и т. д.) в начале и сделать некоторые предположения, основанные на количестве пробелов, о том, как выглядит имя. составил.

Я не думаю, что есть способ проанализировать со 100% точностью.

Пытаться www.адрес-парсер.com.Мы используем их веб-сервис, который вы можете протестировать онлайн.

По данным выборки:

  1. Я бы начал с конца строки.Разберите почтовый индекс (любой формат).Прочитайте конец первого пробела.Если почтовый индекс не найден Ошибка.

  2. Затем обрежьте конец для пробелов и специальных символов (запятых).

  3. Затем перейдите к состоянию, снова используйте пробел в качестве разделителя.Возможно, используйте список поиска для проверки двухбуквенных кодов штатов и полных названий штатов.Если допустимое состояние не найдено, возникает ошибка.

  4. Снова обрежьте пробелы и запятые с конца.

  5. Город становится сложнее, я бы поставил здесь запятую, рискуя получить слишком много данных о городе.Найдите запятую или начало строки.

  6. Если в строке еще остались символы, поместите все это в поле адреса.

Это не идеально, но это должно быть довольно хорошей отправной точкой.

Если это данные, введенные человеком, вы потратите слишком много времени, пытаясь обойти исключения.

Пытаться:

  1. Регулярное выражение для извлечения почтового индекса

  2. Поиск почтового индекса (через соответствующую правительственную базу данных), чтобы получить правильный адрес

  3. Попросите стажера вручную проверить соответствие новых данных старым.

Это не решит вашу проблему, но если вам нужны только данные о широте и долготе для этих адресов, API Карт Google довольно хорошо разберет неформатированные адреса.

RecogniContact — это COM-объект Windows, который анализирует адреса в США и Европе.Вы можете попробовать это прямо сейчасhttp://www.loquisoft.com/index.php?page=8

Возможно, вы захотите это проверить! http://jgeocoder.sourceforge.net/parser.htmlДля меня это сработало как шарм.

Проблемы такого типа трудно решить из-за скрытой неоднозначности данных.

Вот решение на основе Perl, которое определяет дерево грамматики рекурсивного спуска на основе регулярных выражений для анализа многих допустимых комбинаций уличных адресов: http://search.cpan.org/~kimryan/Lingua-EN-AddressParse-1.20/lib/Lingua/EN/AddressParse.pm .Сюда входят вложенные свойства внутри адреса, такие как:12 1st Avenue N Suite # 2 Где-то Калифорния 12345 США

Это похоже на http://search.cpan.org/~timb/Geo-StreetAddress-US-1.03/US.pm упомянуто выше, но также работает для адресов за пределами США, таких как Великобритания, Австралия и Канада.

Вот результат для одного из ваших примеров адресов.Обратите внимание, что сначала необходимо удалить раздел имени из «A.П.Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947», чтобы сократить его до «2299 Lewes-Georgetown Hwy, Georgetown, DE 19947».Этого легко достичь, удалив все данные до первого числа, найденного в строке.

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'

Поскольку в слове существует вероятность ошибки, подумайте об использовании SOUNDEX в сочетании с алгоритмом LCS для сравнения строк, это очень поможет!

используя API 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);

Для разработчиков Ruby или Rails есть хороший драгоценный камень под названием адрес улицы.Я использовал это в одном из своих проектов, и он выполняет необходимую мне работу.

Единственная проблема, с которой я столкнулся, заключалась в том, что адрес был в этом формате. P. O. Box 1410 Durham, NC 27702 он вернул ноль, и поэтому мне пришлось заменить «P.О.Box" с '', и после этого он смог его проанализировать.

Существуют службы передачи данных, которые, зная почтовый индекс, предоставят вам список названий улиц в этом почтовом индексе.

Используйте регулярное выражение для извлечения почтового индекса или штата города — найдите правильный или в случае ошибки получите оба.вытащить список улиц из источник данных Исправьте город и штат, а затем адрес.Как только вы получите действительную адресную строку 1, город, штат и почтовый индекс, вы сможете сделать предположения по адресной строке 2..3.

Я не знаю, НАСКОЛЬКО это было бы ВОЗМОЖНО, но я не видел упоминания об этом, поэтому решил пойти дальше и предложить следующее:

Если вы находитесь строго в США...получите огромную базу данных всех почтовых индексов, штатов, городов и улиц.Теперь найдите их в своих адресах.Вы можете проверить то, что вы нашли, проверив, существует ли, скажем, найденный вами город в том штате, который вы нашли, или проверив, существует ли найденная вами улица в найденном вами городе.Если нет, то скорее всего, это не улица Джона, а имя адресата...По сути, получите как можно больше информации и сверьте с ней свои адреса.Крайним примером может быть получение СПИСКА ВСЕХ АДРЕСОВ В США А, а затем определение того, какой из них наиболее соответствует каждому из ваших адресов...

Существует порт javascript для пакета perl Geo::StreetAddress::US: https://github.com/hassansin/parse-адрес .Он основан на регулярных выражениях и работает довольно хорошо.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top