php实现地址自动识别

文章热词:php,地址自动识别

日期:2019-06-14 09:03 by 杨国伟 588 1 收藏
我要分享

摘要:地址自动识别现在普遍,特别是用在快递填写地址,姓名,手机号码的时候,会把这些按照一定的规范填写后,点击自动识别后,会自动填写到各自的input。最近也简单的实现了这个功能,给后台添加用户的时候,自动识别地址。

具体问题具体分析!代码实现基于laravel完成。一个laravel完整的功能得具备这些:路由route,Model, View, Controller, 我这里用的有依赖注入服务容器等功能,当然,用到地址,你首先要有地址库。。。

下面来看看是如何实现的,这里我只贴出核心代码

UsersController控制器

在这里新建构造函数,实现容器的依赖注入UsersRepository

/** @var  UserRepository */
private $userRepository;
public function __construct(UsersRepository $userRepo)
{
    $this->userRepository = $userRepo;
}

接下来就新建地址识别的方法,  $discernDel   接收的数据是从前端传过来的,后面再贴前端代码。  业务代码处理交给容器UsersRepository里的方法getDiscern处理

/**
 * Function:地址识别
 * Author:cyw0413
 * @param Request $request
 * @return IlluminateContractsRoutingResponseFactory|IlluminateHttpResponse|
 * LaravelLumenHttpResponseFactory|SymfonyComponentHttpFoundationResponse
 */
public function getDiscern(Request $request)
{
    $discernDel = $request->input(discernDel);
    try{
       DB::beginTransaction();
       $address = $this->userRepository->getDiscern($discernDel);
       DB::commit();
    }catch (Exception $e){
        DB::rollBack();
        $msg = "信息提示:".$e->getMessage().",行:".$e->getLine();
        return response([code => 0, msg=>$msg]);
    }
    return response([code=>1,msg=>$address]);   //地址识别完成
}

来看看userRepository容器处理地址识别的各种业务代码

/**
 * Function:识别地址
 * Author:cyw0413
 */
public function getDiscern($discernDel)
{
    if (empty($discernDel)) {
        throw new  Exception("请传入要识别的地址");
    }
    $discernDel_left = explode ([, $discernDel);
    if (!isset($discernDel_left[1])) {
        throw new  Exception("你填写的地址规则错误,手机号码应该用[]");
    }
    $discernDel_right = explode (], $discernDel_left[1]);
    if (!isset($discernDel_right[1]) || empty($discernDel_right[1])) {
        throw new  Exception("你填写的地址规则错误,手机号码应该用[]");
    }
    $name = $discernDel_left[0];
    if (empty($name)) {
        throw new  Exception("你填写的姓名有误!");
    }
    $mobile = $discernDel_right[0];
    if (empty($mobile) || checkMobile($mobile) == 0) {
        throw new  Exception("你填写的手机号码格式有误!");
    }
    $address = trim ($discernDel_right[1]);
    if (empty($address)) {
        throw new  Exception("你填写的地址不能为空");
    }
    $var_address = $this->getAddressArrar($address);
    $var_address[name] = $name;
    $var_address[mobile] = $mobile;
    return $var_address;
}

上面的方法处理手机,名称,和地址处理,地址处理有些繁杂,因为有时候填写的地址有不一样的,比如广西省,有些就填写广西壮族自治区,所以getAddressArrar方法处理地址匹配信息,根据自己的业务做调整,如下

/**
 * Function:地址的处理
 * Author:cyw0413
 * @param $address
 * @return array
 * @throws Exception
 */
function getAddressArrar($address){
    // 获取所有地址递归列表
    $regions = $this->getRegions();
    // 初始化数据
    $province = $city = $district = [];
    // 先查找省份-第一级地区
    $province = $this->checkAddress($address, $regions);
    if($province){
        $province_arr = [110000,300000,404100,310000];  //4个市辖区如果地址不存在二级(市辖区,县),则特殊处理
        if(!isset($province[region_code])){
            throw new Exception("请正确填写省份(市辖区)");
        }
        // 查找城市-第二级地区
        $city = $this->checkAddress($address, $province[list]);
        //这里只处理4个市辖区,可能还有多种情况,待发现
        if(in_array($province[region_code],$province_arr)  && count($city[list]) == 0){
            $city = $this->checkAddress(市辖区, $province[list]);
            if($city){
                // 查找地区-第三级地区
                $district = $this->checkAddress($address, $city[list]);
                //如果没有找到,则查找另外一个二级地区
                if(!isset($district[region_code])){
                    $city = $this->checkAddress(县, $province[list]);
                    // 查找地区-第三级地区
                    $district = $this->checkAddress($address, $city[list]);
                }
            }
        }else{
            if($city){
                // 查找地区-第三级地区
                $district = $this->checkAddress($address, $city[list]);
            }
        }
    }else{
        //省份不填,报错误
        throw new Exception("省份没填写,请检查");
    }
    return $this->getAddressInfo($address, $province, $city, $district);
}
/**
 * 匹配正确的城市地址
 * @param $address
 * @param $city_list
 * @param int $force
 * @param int $str_len
 * @return array
 **/
function checkAddress($address, $city_list, $force=false, $str_len=2){
    $num = 0;
    $list = array();
    $result = array();
    // 遍历所有可能存在的城市
    foreach ($city_list as $city_key=>$city){
        $city_name = mb_substr($city[region_name], 0, $str_len,utf-8);
        // 判断是否存包含当前地址字符
        $city_arr = explode($city_name, $address);
        // 如果存在相关字眼,保存该地址的所有子地址
        if(count($city_arr) >= 2){
            // 必须名称长度同时达到当前比对长度
            if(strlen($city[region_name]) < $str_len){
                continue;
            }
            $num ++;
            if(isset($city[child])){
                $list = $list + $city[child];
            }
            $result[] = array(
                region_code => $city_key,
                region_name => $city[region_name],
                list =>$list,
            );
        }
    }
    // 如果有多个存在,则加大字符匹配长度
    if($num > 1 || $force){
        $region_name1 = $result[0][region_name];
        $region_name2 = $result[1][region_name];
        if(strlen($region_name1) == strlen($region_name2) && strlen($region_name1) == $str_len){
            $region_id1 = $result[0][region_code];
            $region_id2 = $result[1][region_code];
            $index = $region_id1 > $region_id2 ? 1 : 0;
            $result = $result[$index];
            return $result;
        }
        return $this->checkAddress($address, $city_list, $force, $str_len+1);
    } else {
        $result[0][list] = $list;
        return $result[0];
    }
}
/**
 * 根据原地址返回详细信息
 * @param $address
 * @param $province
 * @param $city
 * @param $area
 * @return array
 **/
function getAddressInfo($address, $province, $city, $district){
    // 查找最后出现的地址 - 截取详细信息
    if(!isset($province[region_name])){
        throw new Exception("请检查并正确填写省份(市辖区)");
    }
    if(!isset($city[region_name])){
        throw new Exception("请检查并正确填写城市");
    }
    if(!isset($district[region_name])){
        throw new Exception("请检查并正确填写区域(县/区/镇)");
    }
    $find_str = ;
    if($province[region_name]){
        $find_str = $province[region_name];
        if($city[region_name]){
            $find_str = $city[region_name];
            if(isset($district[region_name]) && $district[region_name]){
                $find_str = $district[region_name];
            }
        }
    }
    // 截取详细的信息
    $find_str_len = mb_strlen($find_str,utf-8);
    for($i=0; $i<$find_str_len-1; $i++){
        $substr = mb_substr($find_str,0,$find_str_len - $i, utf-8);
        $end_index = mb_strpos($address, $substr);
        if ($end_index){
            $address = mb_substr($address, $end_index + mb_strlen($substr) , mb_strlen($address) - $end_index);
        }
    }
    !empty($find_str) && $find_str = |S* . $find_str;
    $area[info] = preg_replace("/s*|,|,|:|:{$find_str}/i", , $address);
    if(empty($area[info])){
        throw new Exception("详细地址不存在,请检查");
    }
    return $address = [
        province => $province[region_code],
        city     => $city[region_code],
        district => $district[region_code],
        info     => $area[info]
    ];
}

前端html部分代码

基本上能看得懂的。jquery用到 getDiscern();方法,手机号码,姓名,地址等input这里就不一一列出了。大家根据下面的jquery都能想象到

<div class="form-group">
   {!! Form::label(discern, 自动识别地址:,[class => control-label col-sm-2]) !!}
   <div class="col-sm-5">
      {!! Form::textarea(discern, , [class => form-textarea form-control form-discern,rows => 3]) !!}
   </div>
   <div class="col-sm-3" style="height: 75px;">
      <button type="button" class="btn btn-info btn-sm discern" onclick="getDiscern();" >提交识别</button>
      <small class="ruleGet" style="color: #676a74;">*查看模板</small>
   </div>
</div>

jquery代码部分

ajax post后交给url:getDiscern 处理,这个就是上面controller的方法,success返回的数据后再追加到每个input里,最后再清除掉自动识别地址框的数据

/**
 * 地址识别
 * @returns {boolean}
 */
function getDiscern(){
    var discernDel = $(".form-discern").val();
    if(!discernDel){
        alert("请输入要识别的地址");
        return false;
    }
    $.ajax({
        type: POST,
        url: "{!! route(admin.user.getDiscern) !!}",
        data: {
            _token: csrf_token(),
            discernDel: discernDel
        },
        dataType: json,
        timeout: 50000,
        success: function (res) {
            if (res.code == 1) {
                $("input[name=addr[linkman]]").val(res.msg.name);
                $("input[name=user_name]").val(res.msg.mobile);
                $("input[name=addr[address]]").val(res.msg.info);
                //触发change事件
         $(#province).val(res.msg.province).trigger(change);
                $(#city).val(res.msg.city).trigger(change);
                $(#area).val(res.msg.district).trigger(change);
                //识别后清除
         $(".form-discern").val("");
            } else {
                alert(res.msg);
            }
        }
    })
}

上一篇:php使用curl并发减少后端访问时间的方法

下一篇:git的4个阶段的撤销更改你必须要弄懂


评论