js智能识别收货地址

作者: 分类: 前端 发布时间: 2022-08-07 10:32 浏览人数:5
 

时隔接近一年的时间没更新过博客了,今天来更新下~

前段时间做了些前端内容,最近在整理一些稍微有点用的内容。比如智能解析地址,用户只需要输入:张三13800138000广东省深圳市南山区南海大道3688号,就能够解析出姓名、电话、省市区、地址信息了。是不是很方便?

实现原理纯JavaScript,无需JQuery,轻量级的js包,可以参考以下代码:

// 定义所有省级名称
const provinces = ["北京", "天津", "河北", "山西", "内蒙古", "辽宁", "吉林", "黑龙江", "上海", "江苏", "浙江", "安徽", "福建", "江西", "山东", "河南", "湖北", "湖南", "广东", "广西", "海南", "重庆", "四川", "贵州", "云南", "西藏", "陕西", "甘肃", "青海", "宁夏", "新疆", "台湾", "香港", "澳门", "国外"];

// 定义所有省级可能出现的后缀
const provinceKey = ['特别行政区', '维吾尔自治区', '壮族自治区', '回族自治区', '自治区', '省省直辖', '省', '市'];

// 定义所有地级市可能出现的后缀
const cityKey = ['布依族苗族自治州', '苗族侗族自治州', '自治州', '行政单位', '市', '盟', '地区', '县'];

// 定义所有县级可能出现的后缀
const areaKey = ['县', '旗', '海域', '岛', '市', '区'];

// 定义详细地址可能出现的后缀
const addrKey = ['室', '楼', '单元', '元', '号', '幢', '门', '户', '米', '北', '南', '东', '西', '路口', '路', '处', '街道', '街'];

// 自定义去除关键字,可自行添加
const search = ['地址', '收货地址', '收货人', '收件人', '收货', '邮编', '电话', ':', ':', ';', ';', ',', ',', '。', ' '];

// 整理电话格式
const mobileRegexs = [
  /(\d{3})-(\d{4})-(\d{4})/g,
  /(\d{3}) (\d{4}) (\d{4})/g,
];

const mobileReg = /(86-[1][0-9]{10})|(86[1][0-9]{10})|([1][0-9]{10})/g;

// 直辖市
const municipalityDirectly = '北京|天津|重庆|上海';

/**
 * 解析地址
 * @param {Object} obj 
 * @param {String} obj.parseText 要解析的地址文本。
 * @param {function({addr: '富康路姚家园3楼5单元3305室',area: '朝阳区',city: '北京市',mobile: '15000000000',name: '马云',province: '北京市',})=} obj.success
 * @param {function(String)=} obj.fail
 * @param {function({addr: '富康路姚家园3楼5单元3305室',area: '朝阳区',city: '北京市',mobile: '15000000000',name: '马云',province: '北京市',}|String)=} obj.complete
 * @return {()=>void}
 * @example parse({
 * parseText: '北京市朝阳区富康路姚家园3楼5单元3305室马云150-0000-0000',
 * success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 * @example parse({
 * parseText: '北京市朝阳区富康路姚家园3号楼5单元3305室马云15000000000',
 * success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 * @example parse({
 * parseText: '北京市朝阳区富康路姚家园3号楼5单元3305室马云15000000000',success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 * @example parse({
 * parseText: '马云,1351111111,北京市朝阳区富康路姚家园3楼',
 * success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 * @example parse({
 * parseText: '马云1351111111北京市朝阳区富康路姚家园3楼',
 * success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 * @example parse({
 * parseText: '北京市朝阳区富康路姚家园3楼1351111111马云',
 * success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 * @example parse({
 * parseText: '北京市朝阳区富康路姚家园3楼150-0000-0000马云',
 * success(res) {},
 * fail(res) {},
 * complete(res) {}
 * })
 */
function parse({parseText, success=function(){}, fail=function(){}, complete=function(){}}) {
  try {
    if (parseText.trim() === '') {
      throw '无法识别';
    }

    let parse = {
      addr: '',
      area: '',
      city: '',
      mobile: '',
      name: '',
      province: '',
    };

    // 过滤关键字词
    search.forEach(str => {
      parseText = parseText.replace(new RegExp(str, 'g'), '')
    });

    // 先识别出手机或电话号码
    mobileRegexs.forEach(regex => {
      parseText = parseText.replace(regex, '$1$2$3')
    });

    let mobile = mobileReg.exec(parseText);
    if (mobile) {
      parse.mobile = mobile[0];
      // 识别完电话手机号码,要把对应的号码从待识别里面去掉
      parseText = parseText.replace(mobile[0], '')
    }

    // 地区地址
    let address = parseText;

    // 检测是哪个省份或直辖市
    for (let i in provinces) {
      let index = address.indexOf(provinces[i]);

      if (index > -1) {
        address = address.substring(index);
      }

      /**
       * 如果地址是直辖市,如“北京市朝阳区”,则补全为“北京市北京市朝阳区”。否则下面的正则表达式匹配不到
       * 但如果地址是“北京市北京市朝阳区”,则不能再修改了
       */
      if (new RegExp(municipalityDirectly, 'g').test(address) && address.match(new RegExp(municipalityDirectly, 'g')).length === 1) {
        let tmp = address.substring(0, 2) + '市' + address;

        parseText = parseText.replace(new RegExp(address, 'g'), tmp);
        
        address = tmp;
      }
    }

    // 匹配地址的正则表达式。包含:省级、地级市级、县级、详细地址等四部分
    let addrRegex = '(.*?)';

    // 省级
    addrRegex = addrRegex + '(?';
    provinceKey.forEach(item=>{
      addrRegex = addrRegex + '[^'+item+']+'+item+'|';
    });
    addrRegex = addrRegex.substring(0, addrRegex.length-1);
    addrRegex = addrRegex + ')';

    // 地级市级
    addrRegex = addrRegex + '(?';
    cityKey.forEach(item=>{
      addrRegex = addrRegex + '[^'+item+']+'+item+'|';
    });
    addrRegex = addrRegex.substring(0, addrRegex.length-1);
    addrRegex = addrRegex + ')';

    // 县级
    addrRegex = addrRegex + '(?';
    areaKey.forEach(item=>{
      addrRegex = addrRegex + '[^'+item+']+'+item+'|';
    });
    addrRegex = addrRegex.substring(0, addrRegex.length-1);
    addrRegex = addrRegex + ')';

    // 详细地址
    addrRegex = addrRegex + '(?';
    addrKey.forEach(item=>{
      addrRegex = addrRegex + '[^'+item+']+'+item+'|';
    });
    addrRegex = addrRegex + '.*?';
    addrRegex = addrRegex + ')';

    // 地址的匹配结果
    let addrRet = address.match(new RegExp(addrRegex));

    if (new RegExp(addrRegex, 'g').test(address)) {
      parse.province = addrRet.groups.province;
      parse.city = addrRet.groups.city;
      parse.area = addrRet.groups.county;
      parse.addr = addrRet.groups.village;
      // 去掉手机电话号码和地址之后,剩下的就是姓名了
      parseText = parseText.replace(new RegExp(addrRet[0], 'g'), '');
    }

    // 姓名
    parse.name = parseText;

    let flag = false;
    for (let i in parse) {
      if (parse[i]) {
        flag = true;
      }
    }

    if (flag) {
      complete && complete(parse);
      success && success(parse);
    } else {
      throw '识别失败';
    }
  } catch (err) {
    complete && complete(err);
    fail && fail(err);
  }
}

module.exports.parse = parse;


下面介绍部分使用实例:

微信小程序:

wxml:

<view class="address">
  <view class="address-item address-item2 address-header">
    <view class="address-label">智能识别view>
    <view class="address-parse-btn" bindtap="identifyParseText">识别view>
  view>
  <view class="address-item address-item2">
    <textarea cols="30" rows="5" class="address-input1" placeholder="智能填写,请粘贴文本" placeholder-class="address-input1_plaeholder" bindinput="changeParseText">textarea>
  view>
view>

js:

const addressParse = require('/utils/address-parse.js');
Page({
  identifyParseText() {
    const that = this;
    wx.showLoading({
      title: '文本提取中',
    });
    let parseText = that.data.parseText;
    addressParse.parse({
      parseText: parseText,
      complete: function () {
        wx.hideLoading();
      },
      success: function (res) {
        wx.showToast({
          title: '识别成功',
          icon: 'none',
        });
        console.log('识别结果:', res);
      },
      fail: function (res) {
        console.log(res);
        if (typeof res === 'string') {
          wx.showToast({
            title: res,
            icon: 'none',
          })
        }
      },
    })
  },
});


使用起来非常方便,容错率也相对比较高。

到此这篇关于js识别地址智能解析的文章就介绍到这里啦~

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!