4

假设我有这个字符串:

<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 中完成此任务?

4

6 回答 6

23

在与你的相似的十二个不同的字符串上尝试了这个,它工作得很好:

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;
于 2013-01-02T00:16:40.920 回答
2

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

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

于 2012-12-30T00:15:15.797 回答
2

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

/[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"]

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

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

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

于 2012-12-30T13:34:44.327 回答
1

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

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

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

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

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

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

于 2013-01-01T20:16:44.087 回答
0

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

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

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

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

于 2013-07-17T04:48:02.887 回答
-1

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

于 2013-01-01T10:41:00.157 回答