Синтаксический анализ используемого адреса улицы, города, штата, Zip из строки [закрыто]
проблема: у меня есть поле адреса из базы данных Access, которая была преобразована в Sql Server 2005. Это поле имеет все в одном поле. Мне нужно разобрать отдельные разделы адреса в соответствующие поля в нормализованной таблице. Мне нужно сделать это примерно для 4 000 записей, и это должно быть повторяемо.
предположения:
предположим, что адрес в США (на данный момент)
предположим, что входная строка иногда будет содержать адресата (адресата) и/или второй адрес улицы (например, Suite B)
государства могут быть сокращены
почтовый индекс может быть стандартным 5-значным или zip+4
в некоторых случаях есть опечатки
UPDATE: в ответ на поставленные вопросы стандарты не соблюдались повсеместно, мне нужно хранить индивидуальные значения, а не просто геокод и ошибки означают опечатку (исправлено выше)
Пример Данных:
A. P. Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947
11522 Шони дороге, Гринвуд-де-19950
шоссе 144 цари, С. В. Довер, Делавэр 19901
Интегрированный Const. Услуги 2 Penns Way Suite 405 новый замок, DE 19720
Humes Realty 33 Уздечка Ридж Court, Lewes, DE 19958
раскопки Николса 2742 Pulaski Hwy Ньюарк, 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
24 ответов
Я проделал большую работу над этим видом синтаксического анализа. Поскольку есть ошибки, вы не получите 100% точности, но есть несколько вещей, которые вы можете сделать, чтобы получить большую часть пути, а затем сделать визуальный тест BS. Вот общий путь к этому. Это не код, потому что писать его довольно академично, нет ничего странного, просто много обработки строк.
(теперь, когда вы опубликовали некоторые примеры данных, я внес некоторые незначительные изменения)
- работа назад. Начать из почтового индекса, который будет ближе к концу, и в одном из двух известных форматов: XXXXX или XXXXX-XXXX. Если это не отображается, вы можете предположить, что находитесь в части города, штата, ниже.
- следующее, Перед zip, будет состояние, и это будет либо в двухбуквенном формате, либо в виде слов. Вы также знаете, что это будет-их всего 50. Кроме того, вы можете soundex слова, чтобы помочь компенсировать орфографические ошибки.
- перед этим город, и это наверное на той же линии, что и штат. Вы могли бы использовать zip-код базы данных чтобы проверить город и штат на основе zip, или, по крайней мере, использовать его в качестве детектора BS.
- Этот адрес будет одна или две линии. Вторая строка обычно будет номером suite, если он есть, но это также может быть PO box.
- это будет почти невозможно обнаружить имя на первой или второй строке, если оно не предваряется номер (или если он имеет префикс " attn:" или " внимание:", это может дать вам подсказку о том, является ли это именем или адресной строкой.
надеюсь, это поможет.
Я думаю, что аутсорсинг проблемы-лучший выбор: отправьте его в геокодер Google (или Yahoo). Геокодер возвращает не только lat/long (которые здесь не представляют интереса), но и богатый анализ адреса с заполненными полями, которые вы не отправляли (включая ZIP+4 и county).
например, разбор" 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 Geo:: StreetAddress: US модуль, используемый геокодер.нас на C#, сбросил его на CodePlex и думаю, что люди, натыкающиеся на этот вопрос в будущем, могут найти его полезным:
на домашней странице проекта я пытаюсь рассказать о его (очень реальных) ограничениях. Поскольку он не поддерживается базой данных USPS valid street адреса, разбор может быть неоднозначным, и он не может ни подтвердить, ни опровергнуть действительность данного адреса. Он может просто попытаться вытащить данные из строки.
это предназначено для случая, когда вам нужно получить набор данных в основном в правильных полях или хотите предоставить ярлык для ввода данных (позволяя пользователям вставлять адрес в текстовое поле, а не вкладывать между несколькими полями). Это не предназначен для проверки доставки адреса.
Это не попытайтесь разобрать что-нибудь выше линии улицы, но, вероятно, можно было бы поработать с регулярным выражением, чтобы получить что-то достаточно близкое-я, вероятно, просто прервал бы его на номере дома.
Я делал это в прошлом.
либо сделайте это вручную (создайте хороший графический интерфейс, который поможет пользователю сделать это быстро), либо автоматизируйте его и проверьте недавнюю адресную базу данных (вы должны купить это) и вручную обработайте ошибки.
ручная обработка займет около 10 секунд каждый, то есть вы можете сделать 3600/10 = 360 в час, поэтому 4000 должно занять у вас примерно 11-12 часов. Это даст вам высокую точность.
для автоматизации нужно недавняя база данных адресов США и настроить свои правила против этого. Я предлагаю не выходить на регулярное выражение (трудно поддерживать долгосрочные, так много исключений). Перейти на 90% совпадение с базой данных, сделать все остальное вручную.
получите копию стандартов почтовой адресации (USPS) вhttp://pe.usps.gov/cpim/ftp/pubs/Pub28/pub28.pdf и обратите внимание, что это 130 + страниц. Regexes для реализации этого было бы орехами.
для международных организаций, все ставки отменяются. Американские рабочие не смогли бы проверить.
кроме того, используйте службу данных. Однако у меня нет рекомендаций.
кроме того: когда вы отправляете материал по почте (это то, для чего он предназначен, верно?) убедитесь, что на конверте (в нужном месте) и обновление базы данных. (Мы сделали простой интерфейс на стойке регистрации человек; человек, который на самом деле сортирует почта)
наконец, когда вы очистили данные, ищите дубликаты.
Я работаю в домене обработки адресов уже около 5 лет, и действительно нет серебряной пули. Правильное решение будет зависеть от ценности данных. Если это не очень ценно, бросьте его через парсер, как предлагают другие ответы. Если это даже несколько ценно, вам обязательно нужно, чтобы человек оценил/исправил все результаты парсера. Если вы ищете полностью автоматизированное, повторяемое решение, вы, вероятно, хотите поговорить с адресом поставщик коррекции, такой как Group1 или Trillium.
после совета здесь я разработал следующую функцию в VB, которая создает проходимые, хотя и не всегда идеальные (если название компании и строка suite приведены, он сочетает в себе люкс и город) полезные данные. Пожалуйста, не стесняйтесь комментировать/рефакторинг/наорать на меня за нарушение одного из моих правил, и т. д.:
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
функция "A. P. Croll & Son 2299 Lewes-Georgetown Hwy, Georgetown, DE 19947" возвращает:
2299 Lewes-Georgetown Hwy A. P. Croll & Son Georgetown DE 19947
SmartyStreets имеет новую функцию, которая извлекает адреса из произвольных входных строк. (Примечание: Я не работаю в SmartyStreets.)
он успешно извлек все адреса из образца ввода, приведенного в вопросе выше. (Кстати, действительны только 9 из этих 10 адресов.)
вот некоторые результаты:
и вот 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 для эти адреса, Google Maps API будет анализировать неформатированные адреса достаточно хороший.
хорошее предложение, в качестве альтернативы вы можете выполнить запрос CURL для каждого адреса в Google Maps, и он вернет правильно отформатированный адрес. От этого, вы можете regex к содержанию вашего сердца.
+1 на предлагаемое решение Джеймс А. Розена как это хорошо для меня, для коллекционеров это увлекательное чтение и лучшей попытке я видел в документировании адресов по всему миру: http://www.columbia.edu/kermit/postal.html
существуют ли какие-либо стандарты вообще в том, как записываются адреса? Например:
- всегда ли есть запятые или новые строки, отделяющие street1 от street2 от города от штата от zip?
- всегда ли прописаны типы адресов (дорога, улица, бульвар и т. д.)? всегда сокращенно? Некоторые из каждой?
- определить "ошибку".
мой общий ответ-это ряд регулярных выражений, хотя сложность этого зависит от ответ. И если нет согласованности вообще, то вы можете достичь только частичного успеха с регулярным выражением (т. е. отфильтровать почтовый индекс и состояние) и должны будете сделать все остальное вручную (или, по крайней мере, пройти через все остальное очень тщательно, чтобы убедиться, что вы заметили ошибки).
еще один запрос для выборки данных.
Как уже упоминалось, я буду работать в обратном направлении от zip.
Как только у вас есть zip, я бы запросил zip-базу данных, сохранил результаты и удалил их и zip из строки.
это оставит вас с беспорядком адреса. Большинство (все?) адреса будут начинаться с числа, поэтому найдите первое вхождение числа в оставшейся строке и возьмите все от него до (Нового) конца строки. Это будет ваш адрес. Все, что находится слева от этого числа, скорее всего, является адресатом.
теперь у вас должны быть город, штат и Zip, хранящиеся в таблице и, возможно, две строки, адресат и адрес. Для адреса проверьте наличие " Suite "или" Apt." п. и разделите это на два значения (адресные строки 1 и 2).
для адресата я бы punt и захватить последнее слово этой строки в качестве фамилии и поместить остальное в поле Имя. Если ты не хочешь ... это вам нужно будет проверить на приветствие (г-н, г-жа, доктор и т. д.) в начале и сделайте некоторые предположения, основанные на количестве пробелов относительно того, как составлено имя.
Я не думаю, что есть какой-либо способ разбора со 100% точностью.
попробовать www.address-parser.com. Мы используем веб-сервис, который можно проверить онлайн
на основе выборочных данных:
Я бы начал с конца строки. Разбор Zip-кода (в любом формате). Читать конец первого пробела. Если почтовый индекс не найден ошибка.
обрезать конец для пробелов и специальных символов (запятых)
затем перейдите в состояние, снова используйте пробел в качестве разделителя. Возможно, используйте список поиска для проверки кодов состояний 2 букв и полных имен состояний. Если не найдено допустимое состояние, ошибка.
снова обрезать пробелы и запятые с конца.
город становится сложным, я бы на самом деле использовал запятую здесь, рискуя получить слишком много данных в городе. Ищите запятую или начало строки.
Если у вас все еще остались символы в строке, вставьте все это в поле адреса.
Это не идеально, но это должно быть довольно хорошей отправной точкой.
Если это данные, введенные человеком, то вы потратите слишком много времени, пытаясь кодировать исключения.
попробуй:
регулярное выражение для извлечения zip-код
поиск почтового индекса (через соответствующую правительственную БД), чтобы получить правильный адрес
получите стажера, чтобы вручную проверить, что новые данные соответствуют старым
Это не решит вашу проблему, но если вам нужны только данные lat/long для этих адресов, Google Maps API будет анализировать неформатированные адреса довольно хорошо.
RecogniContact-это объект Windows COM, который анализирует адреса США и Европы. Ты можешь попробовать прямо сейчас. 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 . Это включает в себя sub свойства в адресе, такие как: 12 1-й проспект N набор # 2 где-то ка-12345 США
это похоже на http://search.cpan.org / ~timb / Geo-StreetAddress-US-1.03 / US.pm упомянутый выше, но также работает для адресов, которые не из США, таких как Великобритания, Австралия и Канада.
вот вывод для одного из ваших примеров адресов. Обратите внимание, что раздел названия необходимо будет сначала удалить из "A. P. 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'
поскольку есть вероятность ошибки в word, подумайте об использовании SOUNDEX в сочетании с алгоритмом LCS для сравнения строк, это очень поможет !
использование 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);
для разработчиков ruby или rails есть хороший драгоценный камень под названием этого свойства. Я использую это в одном из своих проектов, и он выполняет необходимую мне работу.
единственная проблема, которая у меня была, когда адрес находится в этом формате P. O. Box 1410 Durham, NC 27702
Он вернул ноль, и поэтому мне пришлось заменить "P. O. Box" на " и после этого он смог разобрать его.
есть службы данных, которые, учитывая почтовый индекс даст вам список названий улиц в этом почтовом индексе.
используйте регулярное выражение для извлечения Zip или City State-найдите правильный или если ошибка получит оба. вытянуть список улиц с исходные данные исправьте город и штат, а затем адрес улицы. Как только вы получите допустимую адресную строку 1, город, штат и zip, вы можете сделать предположения в адресной строке 2..3
Я не знаю, насколько это возможно, но я не видел, чтобы это упоминалось, поэтому я думал, что я пойду вперед и предложу это:
Если вы находитесь строго в США... получите огромную базу данных всех почтовых индексов, штатов, городов и улиц. Теперь поищите это в своих адресах. Можно проверить, что вы найдете на тестирование, если, скажем, в город вы нашли существует в государстве-вы нашли, или, если на улице вы нашли существует в город вы нашли. Если нет, скорее всего, Джон не для Джона улица, но это имя адресата... В основном, получить максимальную информацию, которую вы можете и проверить свои адреса против него. Крайним примером может быть получение списка всех адресов в США A, а затем найти, какой из них наиболее соответствует каждому из ваших адресов...
существует порт javascript perl Geo::StreetAddress:: US пакет:https://github.com/hassansin/parse-address . Он основан на регулярных выражениях и работает довольно хорошо.