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

 更新时间:2020年7月16日 11:32  点击:1973

去年做了些前端内容,最近在整理一些稍微有点用的内容,比如智能解析地址,用户只要输入:张三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 寄快递内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • JavaScript判断浏览器及其版本信息

    本篇文章主要分享了通过window.navigator来判断浏览器及其版本信息的实例代码。具有一定的参考价值,下面跟着小编一起来看下吧...2017-01-23
  • js实现浏览器打印功能的示例代码

    这篇文章主要介绍了js如何实现浏览器打印功能,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-15
  • php常量详细解析

    一、常量常量是一个简单值的标识符(名字)。如同其名称所暗示的,在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量)。常量默认为大小写敏感。按照惯例常量标识符总是大写的。 常量名和其它任何 PHP 标签遵循...2015-10-30
  • Nest.js参数校验和自定义返回数据格式详解

    这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
  • 利用JS实现点击按钮后图片自动切换的简单方法

    下面小编就为大家带来一篇利用JS实现点击按钮后图片自动切换的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
  • JavaScript预解析,对象详解

    这篇文章主要介绍了JavaScript预解析,对象的的相关资料,小编觉得这篇文章写的还不错,需要的朋友可以参考下,希望能够给你带来帮助...2021-11-10
  • 详解前端安全之JavaScript防http劫持与XSS

    作为前端,一直以来都知道HTTP劫持与XSS跨站脚本、CSRF跨站请求伪造。防御这些劫持最好的方法是从后端入手,前端能做的太少。而且由于源码的暴露,攻击者很容易绕过防御手段。但这不代表我们去了解这块的相关知识是没意义的,本文的许多方法,用在其他方面也是大有作用。...2021-05-24
  • js+css实现回到顶部按钮(back to top)

    这篇文章主要为大家详细介绍了js+css实现回到顶部按钮back to top回到顶部按钮,感兴趣的小伙伴们可以参考一下...2016-03-03
  • JavaScript仿支付宝密码输入框

    那么今天我就用JavaScript代码来实现这个效果吧,那么首先介绍一下整个的思路,首先我们先将确定输入密码的位数,我的需求是5位,那么就用一个div标签包住5个input标签...2016-01-02
  • js实现上传图片及时预览

    这篇文章主要为大家详细介绍了js实现上传图片及时预览的相关资料,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-05-09
  • js实现调用网络摄像头及常见错误处理

    这篇文章主要介绍了js实现调用网络摄像头及常见错误处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-07
  • JS实现随机生成验证码

    这篇文章主要为大家详细介绍了JS实现随机生成验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-06
  • js组件SlotMachine实现图片切换效果制作抽奖系统

    这篇文章主要介绍了js组件SlotMachine实现图片切换效果制作抽奖系统的相关资料,需要的朋友可以参考下...2016-04-19
  • vue.js 表格分页ajax 异步加载数据

    Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.这篇文章主要介绍了vue.js 表格分页ajax 异步加载数据的相关资料,需要的朋友可以参考下...2016-10-20
  • 基于JavaScript实现表单密码的隐藏和显示出来

    为了网站的安全性,很多朋友都把密码设的比较复杂,但是如何密码不能明显示,不知道输的是对是错,为了安全起见可以把密码显示的,那么基于js代码如何实现的呢?下面通过本文给大家介绍JavaScript实现表单密码的隐藏和显示,需要的朋友参考下...2016-03-03
  • js实现列表按字母排序

    这篇文章主要为大家详细介绍了js实现列表按字母排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-11
  • 基于JavaScript实现文字超出部分隐藏

    这篇文章主要介绍了基于JavaScript实现文字超出部分隐藏 的相关资料,需要的朋友可以参考下...2016-03-01
  • JS实现响应鼠标点击动画渐变弹出层效果代码

    这篇文章主要介绍了JS实现响应鼠标点击动画渐变弹出层效果代码,具有非常自然流畅的动画过度效果,涉及JavaScript针对鼠标事件的响应及页面元素样式的动态操作相关技巧,需要的朋友可以参考下...2016-03-28
  • node.JS md5加密中文与php结果不一致怎么办

    这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
  • 浅析AngularJS Filter用法

    系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter。如果对smarty比较熟悉的话,学习angularjs会比较容易一点,这篇文章给大家介绍angularjs filter用法详解,感兴趣的朋友一起学习吧...2015-12-29