JS寄快递地址智能解析的实现代码


Posted in Javascript onJuly 16, 2020

去年做了些前端内容,最近在整理一些稍微有点用的内容,比如智能解析地址,用户只要输入:张三1351111111江苏省扬州市广陵区XX小区X楼xxx室,就能解析出姓名、电话、省市区、地址信息了。是不是很方便?

项目地址暂时没有放,大家可以关注我的个人码云地址https://gitee.com/w9

纯JavaScript,无需Jquery,轻量级的JS包。可参考以下代码:

let defaultData = [];

const mCity = {};

const mArea = {};

/**
 * 处理原始地址数据转换成专用数据
 * @param list 原始数据
 * @param init 是否初始化 如传空 已转换过不会再次转换
 * @returns {boolean}
 */
function parseArea(list, init) {
 if (!init && defaultData.length) {
 return true;
 }
 defaultData = list;
 defaultData.forEach(province => {
 if (province.city) {
  province.city.forEach(city => {
  if (city.name !== '其他') {
   if (!mCity[city.name]) {
   mCity[city.name] = [];
   }
   mCity[city.name].push({
   p: province.name,
   c: city.name,
   a: city.area || []
   });
  }
  if (city.area) {
   city.area.forEach(area => {
   if (area !== '其他') {
    if (!mArea[area]) {
    mArea[area] = [];
    }
    mArea[area].push({
    p: province.name,
    c: city.name
    })
   }
   })
  }
  })
 }
 });
}
/**
 * 解析邮编
 * @param
 * @returns <array>
 */
function zipCodeFormat() {
 let list = []
 zipCode.forEach((el) => {
 if (el.child) {
  el.child.forEach((event) => {
  if (event.child) {
   event.child.forEach(element => {
   list.push(element.zipcode)
   })
  }

  })
 }
 })
 return list;
}

//专用数据处理

let zipCodeList = zipCodeFormat();//邮编
parseArea(areaList);//地址

/**
 * 解析
 * @param address 任意地址字符串
 * @returns {{name: string, mobile: string, detail: string, zip_code: string, phone: string}}
 */
function parse(address) {
 address = address || '';
 const parse = {
 name: '',
 mobile: '',
 detail: '',
 zip_code: '',
 phone: ''
 };


 //去除空格...
 address = address.replace(/\r\n/g, ' ').replace(/\n/g, ' ').replace(/\t/g, ' ');
 address = address.replace(/\s+/g, "");
 //自定义去除关键字,可自行添加
 const search = ['地址', '收货地址', '收货人', '收件人', '收货', '邮编', '电话', ':', ':', ';', ';', ',', ',', '。', ];
 search.forEach(str => {
 address = address.replace(new RegExp(str, 'g'), ' ')
 });
 //多个空格replace为一个
 address = address.replace(/ {2,}/g, ' ');
 //整理电话格式
 address = address.replace(/(\d{3})-(\d{4})-(\d{4})/g, '$1$2$3');

 address = address.replace(/(\d{3}) (\d{4}) (\d{4})/g, '$1$2$3');

 const mobileReg = /(86-[1][0-9]{10})|(86[1][0-9]{10})|([1][0-9]{10})/g;
 const mobile = mobileReg.exec(address);
 if (mobile) {
 parse.mobile = mobile[0];
 address = address.replace(mobile[0], ' ')
 }
 //电话
 const phoneReg = /(([0-9]{3,4}-)[0-9]{7,8})|([0-9]{12})|([0-9]{11})|([0-9]{10})|([0-9]{9})|([0-9]{8})|([0-9]{7})/g;
 const phone = phoneReg.exec(address);
 if (phone) {
 parse.phone = phone[0];
 address = address.replace(phone[0], ' ')
 }

 //邮编(加入门牌号;考虑到重复邮编问题;去除之前简单的六位数字校验)

 for (let index = 0; index < zipCodeList.length; index++) {
 if (address.indexOf(zipCodeList[index]) != -1) {
  let num = address.indexOf(zipCodeList[index]);
  let code = address.slice(num, num + 6);
  parse.zip_code = code;
  address = address.replace(code, '')
 }
 }


 /* 废弃
 const zipReg = /([0-9]{6})/g;
 const zip = zipReg.exec(address);
 if (zip) {
  parse.zip_code = zip[0];
  address = address.replace(zip[0], '')
 } 
 */

 address = address.replace(/ {2,}/, ' ');
 //console.log(address)

 let detail = detail_parse_forward(address.trim());
 if (!detail.city) {
 detail = detail_parse(address.trim());
 if (detail.area && !detail.city) {
  detail = detail_parse(address.trim(), {
  ignoreArea: true
  });
  console.log('smart_parse->ignoreArea(忽略区)');
 } else {
  // console.log('smart_parse');
 }
 //这个待完善
 const list = address.replace(detail.province, '').replace(detail.city, '').replace(detail.area, '').split(' ').filter(str => str);
 //详细住址划分关键字
 //注意:只需要填写关键字最后一位即可:比如单元填写元即可!
 const address_detail_list = ['室', '楼', '元', '号', '幢', '门', '户'];
 if (list.length > 1) {
  list.forEach(str => {
  if (!parse.name || str && str.length < parse.name.length) {
   parse.name = str.trim()
  }
  });
  if (parse.name) {
  detail.addr = detail.addr.replace(parse.name, '').trim()
  }
 } else {//若名字写在详细地址后面,根据address_detail_list进行分割;
  let key = [];
  address_detail_list.forEach((el) => {
  key.push(detail.addr.indexOf(el))
  })
  var max = key.sort(function (a, b) {
  return b - a;
  })[0];
  if (max != -1) {
  let addrBuild = detail.addr.slice(0, max + 1);
  let addrNum = detail.addr.replace(addrBuild, '').replace(/[^0-9]+/g, '');
  let userName = detail.addr.replace(addrBuild + addrNum, '')
  detail.addr = addrBuild + addrNum
  parse.name = userName
  }
 }
 } else {
 if (detail.name) {
  parse.name = detail.name
 } else {
  const list = detail.addr.split(' ').filter(str => str);
  if (list.length > 1) {
  parse.name = list[list.length - 1]
  }
  if (parse.name) {
  detail.addr = detail.addr.replace(parse.name, '').trim()
  }
 }
 }
 parse.province = detail.province;
 parse.city = detail.city;
 parse.area = detail.area;
 parse.addr = detail.addr;
 parse.result = detail.result;
 return parse;
}

/**
 * 正向解析模式
 * 从前到后按 province city addr 逐级筛选
 * 有city的值即可说明解析成功
 * 此模式对地址顺序有要求
 * @param address
 * @returns {{province: string, city: string, area: string, addr: string}}
 */
function detail_parse_forward(address) {
 const parse = {
 province: '',
 city: '',
 area: '',
 addr: '',
 name: '',
 };

 const provinceKey = ['特别行政区', '古自治区', '维吾尔自治区', '壮族自治区', '回族自治区', '自治区', '省省直辖', '省', '市'];
 const cityKey = ['布依族苗族自治州', '苗族侗族自治州', '自治州', '州', '市', '县'];

 for (let i in defaultData) {
 const province = defaultData[i];
 let index = address.indexOf(province.name);
 if (index > -1) {
  if (index > 0) {
  //省份不是在第一位,在省份之前的字段识别为名称
  parse.name = address.substr(0, index).trim();
  }
  parse.province = province.name;
  address = address.substr(index + province.name.length);
  for (let k in provinceKey) {
  if (address.indexOf(provinceKey[k]) === 0) {
   address = address.substr(provinceKey[k].length);
  }
  }
  for (let j in province.city) {
  const city = province.city[j];
  index = address.indexOf(city.name);
  if (index > -1 && index < 3) {
   parse.city = city.name;
   address = address.substr(index + parse.city.length);
   for (let k in cityKey) {
   if (address.indexOf(cityKey[k]) === 0) {
    address = address.substr(cityKey[k].length);
   }
   }
   if (city.area) {
   for (let k in city.area) {
    const area = city.area[k];
    index = address.indexOf(area);
    if (index > -1 && index < 3) {
    parse.area = area;
    address = address.substr(index + parse.area.length);
    break;
    }
   }
   }
   break;
  }
  }
  parse.addr = address.trim();
  break;
 }
 }
 return parse;
}

/**
 * 逆向解析 从后【县,区,旗】往前解析
 * 有地区就能大概返回地址了
 * @param address
 * @param ignoreArea 是否忽视区 因为地址中含有区容易导致匹配错误 例:山东省蓬莱市黄海花园东区西门宝威学堂 曲荣声收15753572456
 * @returns {{province: string, city: string, area: string, name: string, _area: string, addr: string}}
 */
function detail_parse(address, {
 ignoreArea = false
} = {}) {
 const parse = {
 province: '',
 city: '',
 area: '',
 name: '',
 _area: '',
 addr: '',
 };
 let areaIndex = -1,
 cityIndex = -1;

 address = address.replace(' ', ' ');

 if (!ignoreArea && address.indexOf('县') > -1 || !ignoreArea && address.indexOf('区') > -1 || !ignoreArea && address.indexOf('旗') > -1) {
 if (address.indexOf('旗') > -1) {
  areaIndex = address.indexOf('旗');
  parse.area = address.substr(areaIndex - 1, 2);
 }
 if (address.indexOf('区') > -1) {
  areaIndex = address.indexOf('区');
  if (address.lastIndexOf('市', areaIndex) > -1) {
  cityIndex = address.lastIndexOf('市', areaIndex);
  parse.area = address.substr(cityIndex + 1, areaIndex - cityIndex);
  } else {
  parse.area = address.substr(areaIndex - 2, 3);
  }
 }
 if (address.indexOf('县') > -1) {
  areaIndex = address.lastIndexOf('县');
  if (address.lastIndexOf('市', areaIndex) > -1) {
  cityIndex = address.lastIndexOf('市', areaIndex);
  parse.area = address.substr(cityIndex + 1, areaIndex - cityIndex);
  } else {
  parse.area = address.substr(areaIndex - 2, 3);
  }
 }
 parse.addr = address.substr(areaIndex + 1);

 } else {
 if (address.indexOf('市') > -1) {
  areaIndex = address.indexOf('市');
  parse.area = address.substr(areaIndex - 2, 3);
  parse.addr = address.substr(areaIndex + 1);
 } else {
  parse.addr = address
 }
 }

 if (address.indexOf('市') > -1 || address.indexOf('盟') > -1 || address.indexOf('州') > -1) {
 if (address.indexOf('市') > -1) {
  parse._area = address.substr(address.indexOf('市') - 2, 2);
 }
 if (address.indexOf('盟') > -1 && !mCity[parse._area]) {
  parse._area = address.substr(address.indexOf('盟') - 2, 2);
 }
 if (address.indexOf('州') > -1 && !mCity[parse._area]) {
  parse._area = address.substr(address.indexOf('州') - 2, 2);
 }
 }

 parse.area = parse.area.trim();

 if (parse.area && mArea[parse.area]) {
 if (mArea[parse.area].length === 1) {
  parse.province = mArea[parse.area][0].p;
  parse.city = mArea[parse.area][0].c
 } else {
  parse._area = parse._area.trim();
  const addr = address.substr(0, areaIndex);
  const d = mArea[parse.area].find(item => {
  return item.p.indexOf(addr) > -1 || item.c === parse._area;
  });
  if (d) {
  parse.province = d.p;
  parse.city = d.c
  } else {
  parse.result = mArea[parse.area];
  }
 }
 } else {
 if (parse._area) {
  const city = mCity[parse._area];
  if (city) {
  parse.province = city[0].p;
  parse.city = city[0].c;
  parse.addr = address.substr(address.indexOf(parse.city) + parse.city.length + 1);
  parse.area = '';
  for (let i in city[0].a) {
   if (parse.addr.indexOf(city[0].a[i]) === 0) {
   parse.area = city[0].a[i];
   parse.addr = parse.addr.replace(city[0].a[i], '');
   break;
   }
  }
  }
 } else {
  parse.area = '';
 }
 }
 parse.addr = parse.addr.trim();
 return parse
}

/*export {parseArea}

export default parse;*/

下面介绍部分使用实例:

Html

<textarea class="weui-textarea sj_textarea" onchange="smart_parse2()" placeholder="[智能填写] 例如:张三1351111111江苏省扬州市广陵区XX小区X楼xxx室" rows="2"></textarea>

JavaScript

//智能识别地址
  function smart_parse2() {
   var value = $('.sj_textarea').val();
   console.log(parse(value));//这里可以看一下解析出来的内容
   var html = '';
   for (var key in parse(value)) {
    if (parse(value)[key]) {
     html += `<p>` + key + `:` + parse(value)[key] + `</p>`
    }
   }   //把解析的内容在赋值到页面元素中(这儿业务使用的Jq,实际上不需要)
   $('#sj_name').val(parse(value).name);
   $('#sj_phone').val(parse(value).phone);
   $('#city-picker2').val(parse(value).province + ' ' + parse(value).city + ' ' + parse(value).area);
   $('#sj_addr').val(parse(value).addr);
  }

使用起来非常方便,容错率也高。

到此这篇关于JS寄快递地址智能解析的文章就介绍到这了,更多相关js 寄快递内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
jQuery 一个图片切换的插件
Oct 09 Javascript
js输出阴历、阳历、年份、月份、周示例代码
Jan 29 Javascript
JavaScript获取table中某一列的值的方法
May 06 Javascript
JavaScript控制table某列不显示的方法
Mar 16 Javascript
原生js实现日期计算器功能
Feb 17 Javascript
vue.js中proxyTable 转发请求的实现方法
Sep 20 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变opacity实现)
Jan 24 Javascript
微信小程序之下拉列表实现方法解析(附完整源码)
Aug 23 Javascript
TypeScript高级用法的知识点汇总
Dec 17 Javascript
vue基于better-scroll仿京东分类列表
Jun 30 Javascript
vue 里面的 $forceUpdate() 强制实例重新渲染操作
Sep 21 Javascript
node.js通过Sequelize 连接MySQL的方法
Dec 28 Javascript
详解js中的原型,原型对象,原型链
Jul 16 #Javascript
详解Webpack4多页应用打包方案
Jul 16 #Javascript
快速了解Vue父子组件传值以及父调子方法、子调父方法
Jul 15 #Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
Jul 15 #Javascript
TypeScript 引用资源文件后提示找不到的异常处理技巧
Jul 15 #Javascript
微信小程序实现列表的横向滑动方式
Jul 15 #Javascript
JavaScript之scrollTop、scrollHeight、offsetTop、offsetHeight等属性学习笔记
Jul 15 #Javascript
You might like
日本十大最佳动漫,全都是二次元的神级作品
2019/10/05 日漫
thinkphp实现多语言功能(语言包)
2014/03/04 PHP
PHP获取数组长度或某个值出现次数的方法
2015/02/11 PHP
jQuery.validate 常用方法及需要注意的问题
2013/03/20 Javascript
12种不宜使用的Javascript语法整理
2013/11/04 Javascript
按Enter键触发事件的jquery方法实现代码
2014/02/17 Javascript
jQuery filter函数使用方法
2014/05/19 Javascript
jQuery中:file选择器用法实例
2015/01/04 Javascript
使用VS开发 Node.js指南
2015/01/06 Javascript
javascript中一些util方法汇总
2015/06/10 Javascript
JavaScript检测上传文件大小的方法
2015/07/22 Javascript
jquery中表单 多选框的一种巧妙写法
2015/09/06 Javascript
jQuery Real Person验证码插件防止表单自动提交
2015/11/06 Javascript
基于JavaScript实现弹出框效果
2016/02/19 Javascript
实现点击下箭头变上箭头来回切换的两种方法【推荐】
2016/12/14 Javascript
详解Vue2 无限级分类(添加,删除,修改)
2017/03/07 Javascript
uploader秒传图片到服务器完整代码
2017/04/22 Javascript
关于meta viewport中target-densitydpi属性详解(推荐)
2017/08/18 Javascript
vue动态循环出的多个select出现过的变为disabled(实例代码)
2019/11/10 Javascript
Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法
2020/12/25 Vue.js
Python中使用tarfile压缩、解压tar归档文件示例
2015/04/05 Python
Python中unittest模块做UT(单元测试)使用实例
2015/06/12 Python
Python爬虫常用小技巧之设置代理IP
2018/09/13 Python
PyTorch中常用的激活函数的方法示例
2019/08/20 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
Django Docker容器化部署之Django-Docker本地部署
2019/10/09 Python
Python unittest单元测试框架实现参数化
2020/04/29 Python
python实现简单文件读写函数
2021/02/25 Python
新学期家长寄语
2014/01/19 职场文书
小学生开学感言
2014/02/28 职场文书
雷锋式好少年事迹材料
2014/08/17 职场文书
装配车间主任岗位职责
2015/04/08 职场文书
入伍通知书
2015/04/23 职场文书
导游词之黄果树瀑布
2019/09/20 职场文书
html+css实现分层金字塔的实例
2021/06/02 HTML / CSS
如何用六步教会你使用python爬虫爬取数据
2022/04/06 Python