Извлечение адреса из строки в PHP с помощью RegEx - PullRequest
2 голосов
/ 26 декабря 2009

Моя проблема

Я пытаюсь сканировать отдельные ссылки на сайте Палаты представителей США , чтобы найти адреса Вашингтона для всех перечисленных лиц. Проблема в том, что формат вашингтонского адреса время от времени меняется. Иногда встречаются пули, трубы, новые линии и метки, которые затрудняют поиск.


Я пытаюсь сканировать много страниц, чтобы найти адреса, которые в основном похожи:

игнорировать своеобразные пробелы. Это просто, чтобы показать сходство между строками

    1433 Longworth House Office Building Washington,  D.C. 20515
     332 Cannon HOB                      Washington   DC   20515
    1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON,  DC   20515
    1238 Cannon H.O.B. (line return)
    Washington, DC 20515
    8293 Longworth House Office Building • Washington DC • 20515
    8293 Longworth House Office Building | Washington DC | 20515

Каждый из них будет возвращаться индивидуально в окружении множества других текстовых и HTML-тегов. Адреса могут даже содержать
или
внутри самого адреса.

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

Обновление:

Узнав больше о различных способах возникновения этих дней, я решил, что лучше будет использовать менее строгое выражение. Эти адреса были обнаружены с пулями, трубами и символами новой строки. Возможно, было бы лучше использовать выражение, которое сообщает следующее:

[числа] [что угодно] [«вашингтон»] [что угодно] [DC | D.C.] [Что угодно] [пять чисел]

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

До сих пор мне не удавалось сопоставить адреса, найденные на следующих (это лишь некоторые из многих)

Ответы [ 5 ]

2 голосов
/ 26 декабря 2009

РЕДАКТИРОВАТЬ : Кажется, что данные [что-нибудь] между первым набором чисел и «вашингтоном» должны быть немного более ограничительными для правильной работы. Секция [что угодно] не должна содержать никаких чисел, так как числа - это то, что мы используем для определения начала одного из адресов. Это работает для трех сайтов, которые вы нам дали.

Я бы сказал, что лучшим первым шагом было бы удалить все HTML-теги и заменить символьную сущность '':

$input = strip_tags($input);
$input = preg_replace("/ /"," ",$input);

тогда, если адреса соответствуют (близки) указанному вами формату, выполните:

$results= array();
preg_match("/[0-9]+\s+[^0-9]*?\s+washington,?\s*D\.?C\.?[^0-9]+[0-9]{5}/si",$input,$results);
foreach($result[0] as $addr){
    echo "$addr<br/>";
}

Это работает для трех приведенных вами примеров, и $results[0] должен содержать каждый из найденных адресов.

Однако, это не будет работать, например, если в адресе есть «Квартира № 2» или что-то подобное, потому что предполагается, что числа, ближайшие к «Вашингтону», обозначают начало адреса.

Следующий сценарий соответствует каждому из тестовых случаев:

<?php
    $input = "
        1433&nbsp;Longworth House Office Building Washington,  D.C. 20515
         332 Cannon HOB                      Washington   DC   20515
        1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON,  DC   20515
        1238 Cannon H.O.B.
        Washington, DC 20515
        8293 Longworth House Office Building • Washington DC • 20515
        8293 Longworth House Office Building | Washington DC | 20515
    ";
    $input = strip_tags($input);
    $input = preg_replace("/&nbsp;/"," ",$input);

    $results= array();
    preg_match_all("/[0-9]+\s+[^0-9]*?washington,?\s*D\.?C\.?[^0-9]*?[0-9]{5}/si",$input,$results);
    foreach($results[0] as $addr){
        echo "$addr<br/>";
    }
1 голос
/ 14 июня 2013

Для этого созданы инструменты и API. Например, , который работает достаточно хорошо, это LiveAddress от SmartyStreets . Я помог в его разработке, и поэтому я чувствую некоторую вашу боль ... Вот результат из примера, который вы предоставили в своем вопросе:

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,4,69,"1433&nbsp;Longworth House Office Building Washington, D.C. 20515",Y,0,,1433 Longworth House Office Building Washington D,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001330,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
2,75,134,332 Cannon HOB Washington DC 20515,Y,0,,332 Cannon Hob,,Washington DC 20515-3226,Washington,DC,20515,District of Columbia,AAU1,205153226996,,,,Y,38.89106,-77.01132,Zip5,Residential,H,Y,AL,H#Q#
3,139,199,"1641 LONGWORTH HOUSE OFFICE BUILDING WASHINGTON, DC 20515",Y,0,,1641 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001411,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
4,204,247,"1238 Cannon H.O.B.
Washington, DC 20515",Y,0,,1238 Cannon H O B,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001385,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
5,252,316,8293 Longworth House Office Building • Washington DC • 20515,Y,0,,8293 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001934,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#
6,321,381,8293 Longworth House Office Building | Washington DC | 20515,Y,0,,8293 Longworth House Office Building,,Washington DC 20515-0001,Washington,DC,20515,District of Columbia,AAU1,205150001934,,,,Y,38.89106,-77.01132,Zip5,Residential,S,,AL,Q#X#

Потребовалось около 2 секунд. Этот API бесплатный для использования до определенного момента, и могут быть другие, как это; Я рекомендую вам немного осмотреться, чтобы найти оптимальный вариант для вас ... Я гарантирую, что это будет лучше, чем написание собственного регулярного выражения (подсказка: код этого не основан на регулярных выражениях).

1 голос
/ 26 декабря 2009

EDIT:

Посмотрев на упомянутые вами сайты, я думаю, что следующее должно работать. Предполагая, что у вас есть содержимое страницы, которую вы просканировали в переменную с именем $page, вы можете использовать

$subject = strip_tags($page)

для удаления всей разметки HTML со страницы; затем примените регулярное выражение

(\d+)\s*(.*?)\s*washington.{0,5}(DC|D.C.).{0,5}(\d{5})

RegexBuddy генерирует следующий код для этого (я не знаю PHP):

if (preg_match('/(\d+)\s*(.*?)\s*washington.{0,5}(DC|D.C.).{0,5}(\d{5})/si', $subject, $regs)) {
    $result = $regs[0];
} else {
    $result = "";
}

$regs[1] будет содержать содержимое первых захватывающих паренов (чисел) и т. Д.

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

1 голос
/ 26 декабря 2009

Это регулярное выражение использует более гибкий подход к содержанию входной строки. Часть "Вашингтон, округ Колумбия" не была жестко закодирована в этом. Различные части адресов записываются отдельно, весь адрес будет записан в $matches[0].

$input = strip_tags($input);
preg_match('/
(\d++)    # Number (one or more digits) -> $matches[1]
\s++      # Whitespace
([^,]++), # Building + City (everything up until a comma) -> $matches[2]
\s++      # Whitespace
(\S++)    # "DC" part (anything but whitespace) -> $matches[3]
\s++      # Whitespace
(\d++)    # Number (one or more digits) -> $matches[4]
/x', $input, $matches);
0 голосов
/ 26 декабря 2009

Ваш вопрос мне не очень понятен, но если я вас правильно понял, я думаю, вы могли бы использовать DOM-парсер для сопоставления с тегами p, а затем проверить, есть ли у любого из них слово «Вашингтон» или номер телефона соответствует району Вашингтона.

...