PHP使用文本输入中的缩写解析街道地址以进行搜索

PHP使用文本输入中的缩写解析街道地址以进行搜索,php,arrays,regex,parsing,search,Php,Arrays,Regex,Parsing,Search,我需要用PHP解析一个街道地址,一个可能有缩写的字符串。 此字符串来自文本输入。 我需要搜索的字段包括: 街道(字母数字-可能有 建筑(字母数字-可能有 数字(字母数字-可能有 面积(从1到5的数字) 其他(未知字段&用于在数据库中搜索上述所有字段) 例如,用户提交以下文本之一: 街道主干道H7大楼5号1区 st大道大厦H7 5号Ar 5 斯特曼大厦7号 ar5未知的其他搜索参数 街道主干道h7 2b 大街大街大街大街大街 我希望看到的结果是一个数组: [街道]=>主要道路[建筑]=>h7[

我需要用PHP解析一个街道地址,一个可能有缩写的字符串。 此字符串来自文本输入。 我需要搜索的字段包括:

  • 街道(字母数字-可能有
  • 建筑(字母数字-可能有
  • 数字(字母数字-可能有
  • 面积(从1到5的数字)
  • 其他(未知字段&用于在数据库中搜索上述所有字段)
例如,用户提交以下文本之一:

  • 街道主干道H7大楼5号1区
  • st大道大厦H7 5号Ar 5
  • 斯特曼大厦7号
  • ar5未知的其他搜索参数
  • 街道主干道h7 2b
  • 大街大街大街大街大街
  • 我希望看到的结果是一个数组:

  • [街道]=>主要道路[建筑]=>h7[编号]=>5[区域]=>1
  • [街道]=>主要道路[建筑]=>h7[编号]=>5[区域]=>5
  • [街道]=>主楼]=>h7
  • [区域]=>5[其他]=>未知的其他搜索参数
  • [街道]=>主要道路[其他]=>h7 2b
  • [街道]=>主街和主道
  • 到目前为止,我的代码……但与示例3、4、5、6不兼容:

    <?php
    //posted address
    $address = "str main one bldg 5b other param area 1";
    //to replace
    $replace = ['street'=>['st','str'],
                'building'=>['bldg','bld'],
                'number'=>['nr','numb','nmbr']];
    //replace
    foreach($replace as $field=>$abbrs)
        foreach($abbrs as $abbr)
            $address = str_replace($abbr.' ',$field.' ',$address);
    //fields
    $fields = array_keys($replace);
    //match
    if(preg_match_all('/('.implode('|',array_keys($fields)).')\s+([^\s]+)/si', $address, $matches)) {
        //matches
        $search = array_combine($matches[1], $matches[2]);
        //other
        $search['other'] = str_replace($matches[0],"",$address);
    }else{
        //search in all the fields
        $search['other'] = $address;    
    }
    //search
    print_r($search);
    

    哇,你有一堆乱七八糟的东西要清理。我为此花了几个小时。它对你所有的样本都有效,但我不会把我的职业生涯押在它对所有未来案例的完美性上。地址的变化太多了。我希望你能理解我的流程,并在新样本未能正确捕获时修改它我将保留我所有的调试注释,因为我认为您将在以后的编辑中使用它们

    $addresses=array(
        "street Main Road Bulding H7 Number 5 Area 1",
        "st Main Road bldg H7 Nr 5 Ar 5",
        "stMain bldgh7",
        "ar5 unknown other search parameter",
        "street Main Road h7 2b",
        "street main street str main road"
    );
    
    $regex["area"]="/^(.*?)(ar(?:ea)?\s?)([1-5])(.*?)$/i";
    $regex["number"]="/^(.*?)(n(?:umbe)?r\s?)([0-9]+)(.*?)$/i";
    $regex["building"]="/^(.*?)(bu?i?ldi?n?g\s?)([^\s]+)(.*?)$/i";
    $regex["corner"]="/^(.*?str?(?:eet)?)\s?(str?(?:eet)?.*)$/i"; // 2 streets in string
    $regex["street"]="/^(.*?)(str?(?:eet)?\s?)([^\s]*(?:\s?ro?a?d|\s?str?e?e?t?|.*?))(\s?.*?)$/i";
    $regex["other"]="/^(.+)$/";
    
    $search=[];
    foreach($addresses as $i=>$address){
        echo "<br><div><b>$address</b> breakdown:</div>";
        foreach($regex as $key=>$rgx){
            if(strlen($address)>0){
                //echo "<div>addr(",strlen($address),") $address</div>";
                if(preg_match($rgx,$address,$matches)){
                    if($key=="other"){
                        $search[$i][$key]=$matches[0];  // everything that remains
                    }elseif($key=="corner"){
                        $search[$i]["street"]="";  // NOTICE suppression
                        // loop through both halves of corner address omitting element[0]
                        foreach(array_diff_key($matches,array('')) as $half){
                            //echo "half= $half<br>";
                            if(preg_match($regex["street"],$half,$half_matches)){
                                //print_r($half_matches);
                                $search[$i]["street"].=(strlen($search[$i]["street"])>0?"&&":"").ucwords($half_matches[3]);
                                $address=trim($half_matches[1].$half_matches[4]);
                                // $matches[2] is the discarded identifier
                                //echo "<div>$key Found: {$search[$i][$key]}</div>";
                                //echo "<div>Remaining: $address</div>";
                            }
                        }
                    }else{
                        $search[$i][$key]=($key=="street"?ucwords($matches[3]):$matches[3]);
                        $address=trim($matches[1].$matches[4]);
                        // $matches[2] is the discarded identifier
                        //echo "<div>$key Found: {$search[$i][$key]}</div>";
                        //echo "<div>Remaining: $address</div>";
                        //print_r($matches);
                    }
                }
            }else{
                break;  // address is fully processed
            }
        }
        echo "<pre>";
            var_export($search[$i]);
        echo "</pre>";  
    }
    

    …男孩,我很高兴这个项目不属于我。祝你好运!

    哇,你有一堆乱七八糟的东西要清理。我为此辛辛苦苦地工作了几个小时。它对你所有的样品都有效,但我不会把我的职业生涯押在它对所有未来案例的完美上。地址的变化实在太多了。我希望你能理解我的过程如果/当新示例未能正确捕获时,请修改它。我将保留所有调试注释,因为我估计您将在将来编辑时使用它们

    $addresses=array(
        "street Main Road Bulding H7 Number 5 Area 1",
        "st Main Road bldg H7 Nr 5 Ar 5",
        "stMain bldgh7",
        "ar5 unknown other search parameter",
        "street Main Road h7 2b",
        "street main street str main road"
    );
    
    $regex["area"]="/^(.*?)(ar(?:ea)?\s?)([1-5])(.*?)$/i";
    $regex["number"]="/^(.*?)(n(?:umbe)?r\s?)([0-9]+)(.*?)$/i";
    $regex["building"]="/^(.*?)(bu?i?ldi?n?g\s?)([^\s]+)(.*?)$/i";
    $regex["corner"]="/^(.*?str?(?:eet)?)\s?(str?(?:eet)?.*)$/i"; // 2 streets in string
    $regex["street"]="/^(.*?)(str?(?:eet)?\s?)([^\s]*(?:\s?ro?a?d|\s?str?e?e?t?|.*?))(\s?.*?)$/i";
    $regex["other"]="/^(.+)$/";
    
    $search=[];
    foreach($addresses as $i=>$address){
        echo "<br><div><b>$address</b> breakdown:</div>";
        foreach($regex as $key=>$rgx){
            if(strlen($address)>0){
                //echo "<div>addr(",strlen($address),") $address</div>";
                if(preg_match($rgx,$address,$matches)){
                    if($key=="other"){
                        $search[$i][$key]=$matches[0];  // everything that remains
                    }elseif($key=="corner"){
                        $search[$i]["street"]="";  // NOTICE suppression
                        // loop through both halves of corner address omitting element[0]
                        foreach(array_diff_key($matches,array('')) as $half){
                            //echo "half= $half<br>";
                            if(preg_match($regex["street"],$half,$half_matches)){
                                //print_r($half_matches);
                                $search[$i]["street"].=(strlen($search[$i]["street"])>0?"&&":"").ucwords($half_matches[3]);
                                $address=trim($half_matches[1].$half_matches[4]);
                                // $matches[2] is the discarded identifier
                                //echo "<div>$key Found: {$search[$i][$key]}</div>";
                                //echo "<div>Remaining: $address</div>";
                            }
                        }
                    }else{
                        $search[$i][$key]=($key=="street"?ucwords($matches[3]):$matches[3]);
                        $address=trim($matches[1].$matches[4]);
                        // $matches[2] is the discarded identifier
                        //echo "<div>$key Found: {$search[$i][$key]}</div>";
                        //echo "<div>Remaining: $address</div>";
                        //print_r($matches);
                    }
                }
            }else{
                break;  // address is fully processed
            }
        }
        echo "<pre>";
            var_export($search[$i]);
        echo "</pre>";  
    }
    

    我很高兴这个项目不属于我。祝你好运!

    谢谢你的帮助!我想我应该做一些类似于多次预赛的事情

    我刚刚找到了一个PHP扩展,它完全符合我的要求

    这个库是PHP Postal(),需要libpostal。运行PHP时加载库需要15-20秒,之后一切正常

    解析的总执行时间:0.00030-0.00060秒

    house: the book club
    house_number: 100-106
    road: leonard st
    suburb: shoreditch
    city: london
    state_district: greater london
    postcode: ec2a 4rh
    country: united kingdom
    
    输出:

    在这之后,我所要做的就是更换标签并格式化地址


    希望这能帮助其他想用PHP解析地址的人。

    谢谢你的帮助!我想我应该做一些类似多重preg_匹配的事情

    我刚刚找到了一个PHP扩展,它完全符合我的要求

    这个库是PHP Postal(),需要libpostal。运行PHP时加载库需要15-20秒,之后一切正常

    解析的总执行时间:0.00030-0.00060秒

    house: the book club
    house_number: 100-106
    road: leonard st
    suburb: shoreditch
    city: london
    state_district: greater london
    postcode: ec2a 4rh
    country: united kingdom
    
    输出:

    在这之后,我所要做的就是更换标签并格式化地址


    希望这能帮助其他想用PHP解析地址的人。

    @azazazaire我花了几个小时在这个解决方案上,我希望你觉得它令人满意。如果是这样的话,请奖励它绿色的勾号和向上的投票,因为它很有帮助。正则表达式不容易阅读,但复杂的正则表达式通常是这样的。我留下的评论应该可以帮助你使用c理解。祝你好运。投票否决它,因为它是不干净的,不稳定的,至少不是无法维护的。这是因为它采用了错误的方法。正确的做法是强迫用户以应用程序可以处理的方式输入数据。@hek2mgl我同意它将是不稳定的,因为输入可能变化很大。这不是我的错。在什么方面它不是很干净吗?如果你不喜欢内联条件语句,那是个人偏好的问题。它大部分是干的,没有不必要的循环。我发现在我花了几个小时试图帮助某人,并提出了迄今为止唯一有效的解决方案后,对我投反对票是不礼貌的。如果你喜欢,就投反对票,但把我投反对票试图帮助别人似乎是无赖。与其对我投反对票,不如提交你自己的,让OP来决定。反对票的字面意思是“这个答案没有用”。这就是问题所要求的。因此,我的答案不值得投反对票。您试图做的是为一种用于定义地址数据的语言编写语法分析器。但是您或OP没有定义描述该语言的规则。它可以是任何东西。这不起作用,只是错误。正确的做法是指向t点Azazeal我花了几个小时在这个解决方案上,我希望你觉得它令人满意。如果是这样的话,请奖励它绿色的勾号和一个向上的投票,因为它是有帮助的。正则表达式不是很容易阅读,但复杂的正则表达式通常是这样的。我的评论是eft应该可以帮助你理解。祝你好运。投票否决它,因为它是不干净的,不稳定的,至少不是不可维护的。这是因为它采用了错误的方法。正确的做法是强迫用户以应用程序可以处理的方式输入数据。@hek2mgl我同意它会不稳定,因为输入可能变化很大。这是错误的这不是我的错。它在什么方面不干净?如果你不喜欢内联条件语句,那么这是个人偏好的问题。它大部分是干燥的,没有不必要的循环。我发现在我花了几个小时试图帮助某人并提出到目前为止唯一有效的解决方案后,对我投反对票是不礼貌的。如果你愿意,就投反对票e、 但是,因为我试图帮助别人而贬低我,这似乎是无稽之谈