123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- /**
- * 需要解析的地址,type是解析的方式,默认是正则匹配
- * @param address
- * @param options:type: 0:正则,1:树查找, textFilter: 清洗的字段
- * @returns {{}|({area: Array, province: Array, phone: string, city: Array, name: string, detail: Array} & {area: (*|string), province: (*|string), city: (*|string), detail: (Array|boolean|string|string)})}
- * @constructor
- */
- const AddressParse = (address, options, provinceString, cityString, areaString) => {
- const { type = 0, textFilter = [] } = typeof options === 'object' ? options : {};
- if (!address) {
- return {}
- }
- const parseResult = {
- phone: '',
- province: [],
- city: [],
- area: [],
- detail: [],
- name: '',
- };
- address = cleanAddress(address, textFilter);
- // 识别手机号
- const resultPhone = filterPhone(address);
- address = resultPhone.address;
- parseResult.phone = resultPhone.phone;
- const resultCode = filterPostalCode(address);
- address = resultCode.address;
- parseResult.postalCode = resultCode.postalCode;
- // 地址分割
- const splitAddress = address.split(' ').filter(item => item).map(item => item.trim());
- // 找省市区和详细地址
- splitAddress.forEach((item) => {
- // 识别地址
- if (!parseResult.province[0] || !parseResult.city[0] || !parseResult.area[0]) {
- // 两个方法都可以解析,正则和树查找
- let parse;
- type === 1 && (parse = parseRegion(item, parseResult));
- type === 0 && (parse = parseRegionWithRegexp(item, parseResult, provinceString, cityString, areaString));
- const {province, city, area, detail} = parse;
- parseResult.province = province || [];
- parseResult.area = area || [];
- parseResult.city = city || [];
- parseResult.detail = parseResult.detail.concat(detail || []);
- } else {
- parseResult.detail.push(item);
- }
- });
- // 地址都解析完了,如果还没有姓名,那么姓名应该是在详细地址里面,取详细地址里面长度最小的那个
- if (!parseResult.name) {
- const detail = JSON.parse(JSON.stringify(parseResult.detail));
- detail.sort((a, b) => a.length - b.length);
- parseResult.name = detail[0];
- const nameIndex = parseResult.detail.findIndex(item => item === parseResult.name);
- parseResult.detail.splice(nameIndex, 1)
- }
- const province = parseResult.province[0];
- const city = parseResult.city[0];
- const area = parseResult.area[0];
- const detail = parseResult.detail;
- return Object.assign(parseResult, {
- province: (province && province.name) || '',
- city: (city && city.name) || '',
- area: (area && area.name) || '',
- detail: (detail && detail.length > 0 && detail.join('')) || ''
- })
- };
- /**
- * 利用正则表达式解析
- * @param fragment
- * @param hasParseResult
- * @returns {{area: (Array|*|string), province: (Array|*|string), city: (Array|*|string|string), detail: (*|Array)}}
- */
- const parseRegionWithRegexp = (fragment, hasParseResult, provinceString, cityString, areaString) => {
- // log('----- 当前使用正则匹配模式 -----')
- let province = hasParseResult.province || [], city = hasParseResult.city || [], area = hasParseResult.area || [],
- detail = [];
- let matchStr = '';
- if (province.length === 0) {
- for (let i = 1; i < fragment.length; i++) {
- const str = fragment.substring(0, i + 1);
- const regexProvince = new RegExp(`\{\"code\":\"[0-9]{1,6}\",\"name\":\"${str}[\u4E00-\u9FA5]*?\"}`, 'g');
- const matchProvince = provinceString.match(regexProvince);
- if (matchProvince) {
- const provinceObj = JSON.parse(matchProvince[0]);
- if (matchProvince.length === 1) {
- province = [];
- matchStr = str;
- province.push(provinceObj)
- }
- } else {
- break
- }
- }
- if (province[0]) {
- fragment = fragment.replace(matchStr, '')
- }
- }
- if (city.length === 0) {
- for (let i = 1; i < fragment.length; i++) {
- const str = fragment.substring(0, i + 1);
- const regexCity = new RegExp(`\{\"code\":\"[0-9]{1,6}\",\"name\":\"${str}[\u4E00-\u9FA5]*?\",\"provinceCode\":\"${province[0] ? `${province[0].code}` : '[0-9]{1,6}'}\"\}`, 'g');
- const matchCity = cityString.match(regexCity);
- if (matchCity) {
- const cityObj = JSON.parse(matchCity[0]);
- if (matchCity.length === 1) {
- city = [];
- matchStr = str;
- city.push(cityObj);
- }
- } else {
- break;
- }
- }
- if (city[0]) {
- const {provinceCode} = city[0];
- fragment = fragment.replace(matchStr, '');
- if (province.length === 0) {
- const regexProvince = new RegExp(`\{\"code\":\"${provinceCode}\",\"name\":\"[\u4E00-\u9FA5]+?\"}`, 'g');
- const matchProvince = provinceString.match(regexProvince);
- province.push(JSON.parse(matchProvince[0]))
- }
- }
- }
- if (area.length === 0) {
- for (let i = 1; i < fragment.length; i++) {
- const str = fragment.substring(0, i + 1);
- const regexArea = new RegExp(`\{\"code\":\"[0-9]{1,6}\",\"name\":\"${str}[\u4E00-\u9FA5]*?\",\"cityCode\":\"${city[0] ? city[0].code : '[0-9]{1,6}'}\",\"provinceCode\":\"${province[0] ? `${province[0].code}` : '[0-9]{1,6}'}\"\}`, 'g');
- const matchArea = areaString.match(regexArea);
- if (matchArea) {
- const areaObj = JSON.parse(matchArea[0]);
- if (matchArea.length === 1) {
- area = [];
- matchStr = str;
- area.push(areaObj);
- }
- } else {
- break
- }
- }
- if (area[0]) {
- const {provinceCode, cityCode} = area[0];
- fragment = fragment.replace(matchStr, '');
- if (province.length === 0) {
- const regexProvince = new RegExp(`\{\"code\":\"${provinceCode}\",\"name\":\"[\u4E00-\u9FA5]+?\"}`, 'g');
- const matchProvince = provinceString.match(regexProvince);
- province.push(JSON.parse(matchProvince[0]));
- }
- if (city.length === 0) {
- const regexCity = new RegExp(`\{\"code\":\"${cityCode}\",\"name\":\"[\u4E00-\u9FA5]+?\",\"provinceCode\":\"${provinceCode}\"\}`, 'g');
- const matchCity = cityString.match(regexCity);
- city.push(JSON.parse(matchCity[0]));
- }
- }
- }
- // 解析完省市区如果还存在地址,则默认为详细地址
- if (fragment.length > 0) {
- detail.push(fragment)
- }
- return {
- province,
- city,
- area,
- detail,
- }
- };
- /**
- * 利用树向下查找解析
- * @param fragment
- * @param hasParseResult
- * @returns {{area: Array, province: Array, city: Array, detail: Array}}
- */
- const parseRegion = (fragment, hasParseResult) => {
- // log('----- 当前使用树查找模式 -----')
- let province = [], city = [], area = [], detail = [];
- if (hasParseResult.province[0]) {
- province = hasParseResult.province
- } else {
- // 从省开始查找
- for (const tempProvince of provinces) {
- const {name} = tempProvince;
- let replaceName = '';
- for (let i = name.length; i > 1; i--) {
- const temp = name.substring(0, i);
- if (fragment.indexOf(temp) === 0) {
- replaceName = temp;
- break;
- }
- }
- if (replaceName) {
- province.push(tempProvince);
- fragment = fragment.replace(replaceName, '');
- break
- }
- }
- }
- if (hasParseResult.city[0]) {
- city = hasParseResult.city
- } else {
- // 从市区开始查找
- for (const tempCity of cities) {
- const {name, provinceCode} = tempCity;
- const currentProvince = province[0];
- // 有省
- if (currentProvince) {
- if (currentProvince.code === provinceCode) {
- let replaceName = '';
- for (let i = name.length; i > 1; i--) {
- const temp = name.substring(0, i);
- if (fragment.indexOf(temp) === 0) {
- replaceName = temp;
- break;
- }
- }
- if (replaceName) {
- city.push(tempCity);
- fragment = fragment.replace(replaceName, '');
- break;
- }
- }
- } else {
- // 没有省,市不可能重名
- for (let i = name.length; i > 1; i--) {
- const replaceName = name.substring(0, i);
- if (fragment.indexOf(replaceName) === 0) {
- city.push(tempCity);
- province.push(provinces.find(item => item.code === provinceCode));
- fragment = fragment.replace(replaceName, '');
- break;
- }
- }
- if (city.length > 0) {
- break;
- }
- }
- }
- }
- // 从区市县开始查找
- for (const tempArea of areas) {
- const {name, provinceCode, cityCode} = tempArea;
- const currentProvince = province[0];
- const currentCity = city[0];
- // 有省或者市
- if (currentProvince || currentCity) {
- if ((currentProvince && currentProvince.code === provinceCode)
- || (currentCity && currentCity.code) === cityCode) {
- let replaceName = '';
- for (let i = name.length; i > 1; i--) {
- const temp = name.substring(0, i);
- if (fragment.indexOf(temp) === 0) {
- replaceName = temp;
- break
- }
- }
- if (replaceName) {
- area.push(tempArea);
- !currentCity && city.push(cities.find(item => item.code === cityCode));
- !currentProvince && province.push(provinces.find(item => item.code === provinceCode));
- fragment = fragment.replace(replaceName, '');
- break;
- }
- }
- } else {
- // 没有省市,区县市有可能重名,这里暂时不处理,因为概率极低,可以根据添加市解决
- for (let i = name.length; i > 1; i--) {
- const replaceName = name.substring(0, i);
- if (fragment.indexOf(replaceName) === 0) {
- area.push(tempArea);
- city.push(cities.find(item => item.code === cityCode));
- province.push(provinces.find(item => item.code === provinceCode));
- fragment = fragment.replace(replaceName, '');
- break;
- }
- }
- if (area.length > 0) {
- break;
- }
- }
- }
- // 解析完省市区如果还存在地址,则默认为详细地址
- if (fragment.length > 0) {
- detail.push(fragment)
- }
- return {
- province,
- city,
- area,
- detail,
- }
- };
- /**
- * 匹配电话
- * @param address
- * @returns {{address: *, phone: string}}
- */
- const filterPhone = (address) => {
- let phone = '';
- // 整理电话格式
- 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');
- address = address.replace(/(\d{4}) \d{4} \d{4}/g, '$1$2$3');
- address = address.replace(/(\d{4})/g, '$1');
- const mobileReg = /(\d{7,12})|(\d{3,4}-\d{6,8})|(86-[1][0-9]{10})|(86[1][0-9]{10})|([1][0-9]{10})/g;
- const mobile = mobileReg.exec(address);
- if (mobile) {
- phone = mobile[0];
- address = address.replace(mobile[0], ' ')
- }
- return {address, phone}
- };
- /**
- * 匹配邮编
- * @param address
- * @returns {{address: *, postalCode: string}}
- */
- const filterPostalCode = (address) => {
- let postalCode = '';
- const postalCodeReg = /\d{6}/g;
- const code = postalCodeReg.exec(address);
- if (code) {
- postalCode = code[0];
- address = address.replace(code[0], ' ');
- }
- return {address, postalCode}
- };
- /**
- * 地址清洗
- * @param address
- * @returns {*}
- */
- const cleanAddress = (address, textFilter = []) => {
- // 去换行等
- address = address
- .replace(/\r\n/g, ' ')
- .replace(/\n/g, ' ')
- .replace(/\t/g, ' ');
- // 自定义去除关键字,可自行添加
- const search = [
- '详细地址',
- '收货地址',
- '收件地址',
- '地址',
- '所在地区',
- '地区',
- '姓名',
- '收货人',
- '收件人',
- '联系人',
- '收',
- '邮编',
- '联系电话',
- '电话',
- '联系人手机号码',
- '手机号码',
- '手机号',
- ].concat(textFilter);
- search.forEach(str => {
- address = address.replace(new RegExp(str, 'g'), ' ')
- });
- const pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\]\.<>/?~!@#¥……&*()——|{}【】‘;:”“’。,、?]", 'g');
- address = address.replace(pattern, ' ');
- // 多个空格replace为一个
- address = address.replace(/ {2,}/g, ' ');
- return address
- };
- export default AddressParse;
|