从字符串中提取地址

时间:2012-12-30 00:09:26

标签: php javascript jquery

假设我有这个字符串:

<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>

我如何从其中一个字符串中提取地址?这会涉及某种Regex,对吧?

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

有人能指出我正确的方向吗?我将如何在jQuery,JavaScript或PHP中完成此任务?

6 个答案:

答案 0 :(得分:20)

尝试了十二种不同的字符串,这些字符串与你的字符串类似,但效果很好:

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;
}

这假设门牌号至少为两位数,且不大于6位。这也假定邮政编码不是“扩展”形式(例如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;

答案 1 :(得分:2)

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

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

答案 2 :(得分: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"]

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

您可以在文本中开始搜索目标关键字,然后过滤该参数,然后删除您要搜索的信息。

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

答案 3 :(得分:1)

由于方便,尝试使用正则表达式解析所有内容是一个常见的“错误”。但是,正则表达式并不能解决所有问题。在这种情况下,它看起来并不像是在寻找文本中的常规模式,而是某些人会写的“自然”表达,就好像他们正在和你说话一样。这些自然表达不一定遵循任何一致的模式。有些人首先放置appt号码然后建立号码,有些人遗漏城市并跳过邮政编码,有些人可能会把城市,州,国家那么拉链。只是不可能枚举某人可以使用地址烹饪的每种可能的正则表达式模式。

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

  1. 我首先要从左到右(至少用英语)一次一个字地阅读文字。在每个单词中,您将进行一次逻辑测试“这个词可能是地址的开头吗?”。我认为这是建筑物编号或设备/单位/箱号的编号(所以“Box XXX”,“PO BOX XXX”,“PO XXX”,“Unit XXX”,“#XXX”或任何数字超过6位数)。虽然我不知道这是事实上的真实,但我从来没有见过长度为7位数的北美建筑物,这是手机的最低限度。所以我怀疑你可以很容易地找出电话号码与建筑物号码。这个“地址开始”测试可能是一组正则表达式匹配,但我们不匹配整个地址,只测试启动地址的单词或短语。如果没有正则表达式匹配,我甚至可能会说它更简单。

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

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

  4. 最终这种方法可能是一种相当简单的JavaScript方法,可能有几百行代码(我不是PHP人,但我认为它类似)。如果你试图列举所有可能的正则表达式模式,有人可以构建一个地址,你只有数百个这样的地址,它仍然是不可靠的! (如果你试图匹配数百个正则表达式模式,也可能会变慢)。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

我使用 Google地理编码API 获得了最好的运气。尝试考虑地址字符串可能输入的每种可能方式都很困难。

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

我在这里找到了一个关于使用谷歌地理编码API(PHP)进行设置的精彩指南:http://www.andrew-kirkpatrick.com/2011/10/google-geocoding-api-with-php/

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

相关问题