【问题标题】:Extract Address from String in PHP with RegEx使用正则表达式从 PHP 中的字符串中提取地址
【发布时间】:2013-07-04 01:17:30
【问题描述】:

我的问题

我正在尝试爬取US House of Representatives Site 上的各个链接,以查找所有列出的个人的华盛顿地址。问题是华盛顿地址的格式不时变化。有时会出现项目符号、管道、换行符和断点标记,使其难以匹配。


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

忽略特殊的空格。这只是为了显示字符串部分的相似性

1433 朗沃斯大厦办公楼华盛顿特区 20515 332 Cannon HOB 华盛顿特区 20515 1641 朗沃斯办公大楼华盛顿特区 20515 1238大炮H.O.B. (回线) 华盛顿特区 20515 8293 Longworth House 办公大楼 • 华盛顿特区 • 20515 8293 Longworth House 办公楼 |华盛顿特区 | 20515

每一个都将单独返回,并被大量其他文本和 html 标记包围。地址甚至可以在地址本身中包含

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

更新:

在详细了解了这些日子可能出现的各种方式之后,我决定最好使用不太严格的表达方式。这些地址已显示为项目符号、管道和换行符。也许传达以下内容的表达式是最好的:

[数字][anything]["washington"][anything][DC|D.C.][anything][五个数字]

显然这太松了。 anything 块正在引入段落,而我只是对允许任何内容的几个字符感兴趣。

到目前为止,我未能成功匹配以下地址(这些只是众多地址中的一小部分)

【问题讨论】:

  • 很难,因为每个人的地址格式似乎都完全不同。我认为最好的选择是首先从您的输入中删除所有 HTML 标签,然后在我的回答中应用下面提到的正则表达式。那应该会更好。我不懂 PHP,所以我不能告诉你如何去除 HTML 标签,但这肯定已经在 SO 上得到了回答。
  • 当然不是答案,而是一些您可能会感兴趣的阅读,因为您亲身遇到地址问题:mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses

标签: php regex street-address


【解决方案1】:

编辑:似乎第一组数字和“华盛顿”之间的 [任何] 数据必须更加严格才能正常工作。 [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/>";
    }

【讨论】:

  • 用括号包围整个正则表达式是多余的。无论如何,它都会在$matches[0] 中被捕获。
  • 我已经更新了原来的问题,请看一下变化。
【解决方案2】:

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

【讨论】:

  • 这很接近,但它假定总会有一个逗号。请重新评估原始问题中列出的各种格式。
【解决方案3】:

编辑:

查看您提到的网站后,我认为以下内容应该可行。假设你在一个名为$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 修饰符使点匹配换行符,并使正则表达式不区分大小写。

【讨论】:

  • 关闭,但这些“任何东西”可能应该限制为最多 5 个字符。现在,这个正则表达式引入了 [anything] 块下限定的段落。不过是我的错,因为我太含糊了。
  • 没问题,只需将.*? 替换为.{0,5} - 我相应地编辑了我的答案。
  • 以下地址似乎不再匹配:/(\d+).{1,5}washington.{1,5}(DC|D.C.).{1,5}(\d{5})/si
  • 啊,是的,您的示例中的第一个“任何东西”包含超过 5 个字符:`LONGWORTH HOUSE OFFICE BUILDING , for example. So I changed that back to .*?. If you need to capture the text here, then enclosed it in parentheses, like (.*?)`。跨度>
  • 哎呀,好点子。不幸的是,这仍然与giffords.house.gov 上的地址不匹配。我目前有:/(\d+).{1,35}\swashington.{1,5}(DC|D.C.).{1,5}(\d{5})/si
【解决方案4】:

为此构建了一些工具和 API。例如,one that works quite well is LiveAddress by SmartyStreets。我帮助开发了它,所以我感受到了你的一些痛苦......这是你在问题中提供的示例的输出:

这是 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在一定程度上是免费使用的,可能还有其他人喜欢它;我鼓励您四处寻找最适合您的选项...我保证这比编写自己的正则表达式更好(提示:其背后的代码不是基于正则表达式)。

【讨论】:

  • 有谁知道任何 PHP 类或 LiveAddress 的其他免费替代品?洛杉矶的效果很好,但对于我正在进行的项目来说成本太高了。
  • @pXdty 嗯...您是否需要将其用于注册的非盈利用途?如果是这样,您可以免费获得 LiveAddress 无限制。否则,我会睁大眼睛,如果我找到一个图书馆,我会告诉你。
  • @pXdty 你能解释一下你正在进行的项目吗?这可能有助于过滤可能的解决方案。总而言之,听起来您想要找到一个可以解析数据源以查找、更正和验证地址的服务(使用来自 USPS 的最新数据),并且您希望该服务非常快速、高度准确- 但也很有侵略性,同时你没有花费,或者花费很少。我是否准确地总结了您要查找的内容?
  • @Jeffrey :我们正在构建一个工具来验证本地搜索列表,这将是免费使用的。是的,我们希望能够解析包含地址的大字符串并向用户提供有效地址。我目前正在使用我编写的非常脏的东西来执行此操作,但它不如 liveaddress 可靠。
  • @pXdty 只需使用this form 注册或联系 SmartyStreets。 (这是题外话,如果您有更多问题,请联系 SS。)系统只会要求您提供链接和/或告诉人们。
【解决方案5】:

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

【讨论】:

  • 来源并不总是有p标签。据我所知,这必须是基于正则表达式的。
猜你喜欢
  • 2015-12-17
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-17
相关资源
最近更新 更多