【问题标题】:Extract address from string从字符串中提取地址
【发布时间】:2012-12-14 18:11:39
【问题描述】:

假设我有这个字符串:

<div>john doe is nice guy btw 8240 E. Marblehead Way 92808  is also</div>

或者这个字符串:

<div>sky being blue? in the world is true? 024 Brea Mall  Brea, California 92821 jackfroast nipping on the firehead</div>

我将如何从这些字符串之一中提取地址?这将涉及某种正则表达式,对吧?

我尝试在网上寻找使用 JavaScript 或 PHP 的解决方案,但无济于事。 Stack Overflow 上没有其他帖子(据我所知)提供使用 jQuery 和/或 Javascript 和/或 PHP 的解决方案。 (最接近的是Parse usable Street Address, City, State, Zip from a string,它在线程中没有任何关于从字符串中提取邮政编码的代码。

有人能指出我正确的方向吗?我将如何在 jQuery、JavaScript 或 PHP 中实现这一点?

【问题讨论】:

  • 这看起来像是正则表达式的情况。我仍然不会帮助你,因为我怀疑你的动机。
  • @Philipp 什么动机?!?
  • 无论您使用哪种语言,都需要一组严格的正则表达式过滤器来验证地址......祝你好运......这不会是微不足道的!
  • @Philipp 等等什么?我需要为我的提醒服务解析地址!这是我正在开发的 URL! dumbsearch.com/now2.php当人们输入提醒时,我想检测地址,以便在日期到来时显示提醒以及到达那里需要多少分钟,以及指向Apple Maps的链接。这是一个适用于 iPhone 的网络应用程序,但它也适用于桌面。试试吧!我的大多数其他问题都与此有关!喜欢看stackoverflow.com/questions/14014619/…!在这个问题中,我问我的 MapQuest API 不起作用。
  • @Philipp 你为什么要删除你的评论?

标签: php javascript jquery


【解决方案1】:

在与您的相似的 12 个不同的字符串上进行了尝试,效果很好:

function str_to_address($context) { 

    $context_parts = array_reverse(explode(" ", $context)); 
    $zipKey = ""; 
    foreach($context_parts as $key=>$str) { 
        if(strlen($str)===5 && is_numeric($str)) { 
            $zipKey = $key;
            break; 
        }
    }

    $context_parts_cleaned = array_slice($context_parts, $zipKey); 
    $context_parts_normalized = array_reverse($context_parts_cleaned); 
    $houseNumberKey = ""; 
    foreach($context_parts_normalized as $key=>$str) { 
        if(strlen($str)>1 && strlen($str)<6 && is_numeric($str)) { 
            $houseNumberKey = $key;
            break; 
        }
    }

    $address_parts = array_slice($context_parts_normalized, $houseNumberKey);
    $string = implode(' ', $address_parts);
    return $string;
}

这假定门牌号至少为两位数,且不超过六位。这也假设邮政编码不是“扩展”形式(例如 12345-6789)。然而,这可以很容易地修改以适应该格式(正则表达式在这里是一个不错的选择,例如 (\d{5}-\d{4})

但是使用正则表达式来解析用户输入的数据...这里不是一个好主意,因为我们只是不知道用户将输入什么,因为(可以假设)没有验证。

浏览代码和逻辑,从从上下文创建数组并获取 zip 开始:

// split the context (for example, a sentence) into an array, 
// so we can loop through it. 
// we reverse the array, as we're going to grab the zip first. 
// why? we KNOW the zip is 5 characters long*.
$context_parts = array_reverse(explode(" ", $context));  

// we're going to store the array index of the zip code for later use 
$zipKey = ""; 

// foreach iterates over an object given the params, 
// in this case it's like doing... 
// for each value of $context_parts ($str), and each index ($key)
foreach($context_parts as $key=>$str) { 

    // if $str is 5 chars long, and numeric... 
    // an incredibly lazy check for a zip code...
    if(strlen($str)===5 && is_numeric($str)) {  
        $zipKey = $key;

        // we have what we want, so we can leave the loop with break
        break; 
    }
}

做一些整理,这样我们就有更好的对象来装门牌了

// remove junk from $context_array, since we don't 
// need stuff after the zip
$context_parts_cleaned = array_slice($context_parts, $zipKey); 

// since the house number comes first, let's go back to the start
$context_parts_normalized = array_reverse($context_parts_cleaned);

然后让我们使用与邮政编码相同的基本逻辑来获取门牌号:

$houseNumberKey = ""; 
foreach($context_parts_normalized as $key=>$str) { 
    if(strlen($str)>1 && strlen($str)<6 && is_numeric($str)) { 
        $houseNumberKey = $key;
        break; 
    }
}

// we probably have the parts we for the address.
// let's do some more cleaning 
$address_parts = array_slice($context_parts_normalized, $houseNumberKey);

// and build the string again, from the address
$string = implode(' ', $address_parts);

// and return the string
return $string;

【讨论】:

  • 哇!感谢您的回复!好全面!!!太描述了!太好了! (顺便说一句,我给了你 100 分的赏金,所以现在你的声望是 +100 :))我也将你的答案标记为正确,并对其进行了投票。它适用于每个测试,天气它在字符串中有其他数字,或者它没有! :)
  • 再次感谢您的精彩回复!
  • 不,但你的天才!我在任何地方都找不到类似的脚本!
  • 有时最好的解决方案往往是最简单的。 :)
  • :) 好的,再次感谢。 :) 我很高兴我能给你 +100 代表。 :)
【解决方案2】:

正则表达式用于针对模式进行测试。你需要知道你在寻找什么模式。从您提供的两个示例中,我会查找一个数字,然后是一些文本,以五位数字结尾。

所有地址都必须采用这种格式。你不能神奇地从字符串中提取地址。

【讨论】:

  • ...但是有人可以提供一个示例正则表达式来查找这个吗? (数字,文本,以 5 位数字结尾)
  • 这个线程:stackoverflow.com/questions/16413/… 提供了一些很好的指针,可以找到哪些匹配项......但我想要一个示例正则表达式代码在行动......谢谢! (PS 你得到我的支持)
【解决方案3】:

如果你所有的地址以数字开头和结尾,你可以使用这个正则表达式来提取你需要的数据:

/[0-9].+[0-9]/gi

Javascript 示例:

"<div>john doe is nice guy btw 8240 E. Marblehead Way 92808  is also</div>".match(/[0-9].+[0-9]/gi) // ["8240 E. Marblehead Way 92808"]
"<div>sky being blue? in the world is true? 024 Brea Mall  Brea, California 92821 jackfroast nipping on the firehead</div>".match(/[0-9].+[0-9]/gi) // ["024 Brea Mall  Brea, California 92821"]

对于包含电话号码的新示例,您可以:

/[0-9].*[0-9]/gi

Javascript 示例:

"john doe 7143138656 is 8240 e marblehead way 92808".match(/[0-9].*[0-9]/gi) // ["7143138656 is 8240 e marblehead way 92808"]

但这只有在您每行都有匹配信息时才会对您有所帮助。如果您真的需要一个强大的地址匹配器,您将需要继续,并创建强大的分析。

您可以开始在文本中搜索目标关键字,然后过滤段落,然后剥离您要查找的信息。

这不是一个简单的问题,但可以做到,您可以使用多个正则表达式进行某些匹配,但如果地址没有模式,正则表达式将无用,到时您需要更改您的接近。

【讨论】:

  • 谢谢,但这行不通,因为字符串中还有电话号码... :(
  • 请举个例子,你也可以把+换成*直到最后一个数值,这样也会得到数字内的所有行。
  • 非常感谢您的帮助,顺便说一句。 :) 这是一个例子:“john doe 7143138656 is 8240 e marblehead way 92808”
【解决方案4】:

为了方便,尝试使用正则表达式解析所有内容是一个常见的“错误”。然而,正则表达式并不是万能的。在这种情况下,看起来您不是在寻找文本中的常规模式,而是有人会写的“自然”表达,就好像他们在和你说话一样。这些自然的表达方式根本不一定遵循任何一致的模式。有些人把appt号码放在前面,然后是建筑物号码,有些人把城市省略了,直接跳到邮政编码,有些人可能把城市、州、国家放在后面。只是不可能枚举某人可以用地址编写的所有可能的正则表达式模式。

对于自然语言地址,我会忘记正则表达式地址检测并转向有状态解析算法。

  1. 我会先从左到右(至少是英文)一次读一个单词。对于每个单词,您都会做一个逻辑测试“这个单词会是地址的开头吗?”。我想这是一个建筑物编号或 appt/unit/box 编号的数字(所以“Box XXX”、“PO BOX XXX”、“PO XXX”、“Unit XXX”、“#XXX”或任何更少的数字长度超过 6 位)。虽然我不知道这是否属实,但我从未见过北美的建筑物编号长度为 7 位数,这是电话的最小值。所以我怀疑你可以很容易地整理出电话号码和建筑物号码。这个“地址开头”测试可能是一组正则表达式匹配,但我们不匹配整个地址,只是测试以地址开头的单词或短语。我什至可能会说没有正则表达式匹配会更简单

  2. 一旦您检测到地址的开始,您就创建了一个“地址解析状态对象”(在您继续解析时用来保存地址的某个类,并跟踪您到目前为止所拥有的内容以及期待下一个)。现在您可以继续单步执行该句子并继续添加到您的解析器状态对象。在建筑物编号之后,我可能会期望街道名称或方向指示符(N. E. W. S. NE. NW. SE. SW.)。如果接下来这些都没有停止您的地址解析并假定地址无效或不完整,请继续寻找地址字的新开头。否则,将街道名称和/或方向指示符添加到您的解析树并继续!

  3. 街道名称后面的任何内容都可以无限变化。一些用户可能只停留在建筑物编号和街道名称(假设他们当地的城市/地区/国家)。否则,您可能正在寻找城市名称或邮政编码/邮政编码。如果找到,则添加到您的地址解析状态对象,如果没有,则假定地址不完整(填写用户默认位置信息?)或无效地址(忽略并继续寻找另一个地址开头?)。

最终,这种方法可能是一种相当简单的 JavaScript 方法,可能只有几百行代码(我不是 PHP 专家,但我认为它会类似)。如果您要尝试枚举所有可能的正则表达式模式,有人可以用它来构造一个地址,那么您将拥有数百个这样的地址,但它仍然不可靠! (如果您尝试匹配数百个正则表达式模式,可能也会很慢)。

【讨论】:

  • 感谢您的回复! :) 有什么可以告诉我一个最适合这个的预制 PHP 解析算法吗?或者为我编写一个基本的 JavaScript 示例?谢谢。 :)
  • @DumbProducts 很高兴这很有帮助。我认为这个网站的本质更多的是通过一些战略帮助/指导帮助你自己做。如果您希望它只是用代码为您编写,请随时单击我的个人资料以找到我的日常工作并购买一些咨询时间。这将是几个小时的工作,我不会在这里免费做。我也要吃饭:-)
【解决方案5】:

我在使用 Google Geocode API 时获得了最好的运气。尝试考虑输入地址字符串的所有可能方式是很困难的。

我最近不得不从一个房地产网站的单个字符串中提取部分地址,我发现最好的选择是使用 google geocode API。它让我可以为输入的每个地址获取街道、城市、州、邮编、纬度、经度等信息。

我在这里找到了有关设置 google geocode API (PHP) 的出色指南:http://www.andrew-kirkpatrick.com/2011/10/google-geocoding-api-with-php/

最好的部分,它甚至可以与地名一起使用。因此,搜索“UCLA”或“Apple 总部”将为您提供您可能需要的地址的所有部分。

【讨论】:

    【解决方案6】:

    我的想法是你应该告诉你的代码“从这里到这里的表格是一个地址,其余的是简单的文本”。为此,您可以创建一个地址数组或将地址保存在数据库中,您可以将其与插入的值进行比较

    【讨论】:

      猜你喜欢
      • 2014-03-25
      • 1970-01-01
      • 1970-01-01
      • 2017-09-15
      • 1970-01-01
      • 2011-02-22
      • 2014-01-31
      • 2017-10-10
      相关资源
      最近更新 更多