使用RegEx从PHP中的字符串中提取地址

时间:2009-12-26 01:18:04

标签: php regex street-address

我的问题

我正在尝试抓取US House of Representatives Site上的各个链接,以查找所有列出的个人的华盛顿地址。问题是华盛顿地址的格式不时变化。有时会有子弹,管道,新线和断裂标签,难以匹配。


我正在尝试抓取多个页面来检索大致相似的地址:

忽略特殊的空白。它仅仅是为了显示字符串部分的相似性

    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标签单独包围。地址甚至可以包含< br>或者< br />在地址本身内。

我想要做的是从源字符串中捕获第一个匹配项,并将其设置为变量的值。根据我的理解,最好用正则表达式来处理。

更新

在更多地了解了这些日子出现的各种方式后,我决定不那么严格的表达方式是最好的。这些地址已经出现了子弹,管道和换行符。也许表达以下信息的表达方式最好:

[数字] [任何] [“华盛顿”] [任何] [DC | D.C。] [任何] [五个数字]

显然这太松了。 任何块都引入了段落,当时我只想让几个字符变成任何字符。

到目前为止,我没有成功匹配以下地址(这些只是其中的一小部分)

5 个答案:

答案 0 :(得分:2)

编辑:好像第一组数字和'华盛顿'之间的[任何]数据必须要更加严格才能正常工作。 [anything]部分不应包含任何数字,因为数字是我们用来分隔其中一个地址的开头。这适用于您提供给我们的三个网站。

我认为最好的第一步是删除所有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]应包含找到的每个地址。​​

然而,这不起作用,例如,如果地址中有“Apartment#2”等,因为它假定最接近'Washington,DC'的数字标记地址的开头。

以下脚本与每个测试用例匹配:

<?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 :(得分:1)

这个正则表达式对输入字符串可以包含的内容采取更灵活的方法。 “华盛顿特区”部分尚未硬编码。地址的不同部分是分开捕获的,整个地址将在$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);

答案 2 :(得分:1)

编辑:

在查看您提到的网站后,我认为以下内容应该有效。假设您拥有在名为$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]将包含第一个捕获parens(数字)的内容,依此类推。

请注意使用/si修饰符使点匹配换行符,并使正则表达式不区分大小写。

答案 3 :(得分:1)

有为此目的而构建的工具和API。例如,one that works quite well is LiveAddress by 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可以免费使用到某个点,也可能有其他类似的;我鼓励你做一些寻找最适合你的选项...我保证它会比编写你自己的正则表达式更好(提示:这不是基于正则表达式的代码隐藏)。

答案 4 :(得分:0)

你的问题对我来说不是很清楚,但是如果我理解正确的话我想你可以使用DOM解析器来匹配p标签,然后检查它们中是否有任何一个有“华盛顿”或者电话号码匹配华盛顿地区。