大家好,我是Echa 。
今天给大家分享非常实用的收货信息智能识别工具,该工具使用广泛,比如小程序,H5,App等等,大大提高用户体验和工作效率。但是市面上大部分都是按照API调用平次来收费的,总体来说比较贵。目前推荐这个是免费的,智能匹配率大概在85%作用,希望大家喜欢。创作不易,喜欢的老铁们加个关注,点个赞,后面会持续更新干货,速速收藏,谢谢!
源码地址:https://gitee.com/JCfeng/js-util/tree/main/address_auto
效果图:
核心代码:
/**
* 收件人信息自动识别
* @param {String} auto_value 输入的信息
* @returns {ReturnInfo}
*/
function address_auto(auto_value) {
/**
* 储存分割后的数据
* @type {String[]}
*/
let split_res = [ auto_value ]
/**
* 支持的分割符
* @type {string[]}
*/
let splitters = [",", ",", " ", "r
", "
"]
// 按不同的分隔符依次分割
for (let splitter of splitters) {
let split_res1 = []
for (let split_res_item of split_res) {
split_res1.push(...split_res_item.split(splitter))
}
split_res = split_res1
}
// 类型标记
// 后面会对每个分割后的部分进行类型检测
let TYPE_MOBILE = 1 << 0 // 手机
let TYPE_NAME = 1 << 1 // 名字
let TYPE_ADDR_PROVINCE = 1 << 2 // 地址-省份部分
let TYPE_ADDR_CITY = 1 << 3 // 地址-城市部分
let TYPE_ADDR_COUNTY = 1 << 4 // 地址-区县部分
let TYPE_ADDR_DETAIL = 1 << 5 // 地址-详细地址部分
// 地址中可写可不写的部分
let DISPENSIBLE_PROVINCES = [ "省", "市", "自治区" ]
let DISPENSIBLE_CITYS = [ "市", "地区", "区", "盟", "自治州" ]
let DISPENSIBLE_COUNTYS = [ "林区", "族区", "区", "自治县", "县", "市", "自治旗", "旗" ]
/**
* 储存地区信息的结构
* @typedef {Object} AreaInfo
* @property {String} code - 地区编码
* @property {String} name - 地区名称
* @property {String} name_except_dispensible - 除了dispensible部分后的地区名称
* @property {Number} similarity - 匹配name_except_dispensible时的相似度
*/
/**
* 地区数据处理函数
* @param {Object.} data - 地区数据
* @param {Array.} dispensible_list - 可忽略的内容
* @returns {Array.}}
*/
let area_data_processing = function (data, dispensible_list) {
return Object.entries(data).map(entry => {
let item = {
code: entry[0] + "",
name: entry[1] + "",
name_except_dispensible: entry[1] + "",
similarity: 1,
}
for (let dispensible_item of dispensible_list) {
if (item.name.endsWith(dispensible_item) && item.name.length >= dispensible_item.length + 2) {
item.name_except_dispensible = item.name.substring(0, item.name.length - dispensible_item.length)
item.similarity = item.name_except_dispensible.length / item.name.length
break
}
}
return item
})
}
let provinces = area_data_processing(areaList.province_list, DISPENSIBLE_PROVINCES) // 储存省份信息的数组
let citys = area_data_processing(areaList.city_list, DISPENSIBLE_CITYS) // 储存省份信息的数组
let countys = area_data_processing(areaList.county_list, DISPENSIBLE_COUNTYS) // 储存省份信息的数组
/**
* 匹配到的信息的结构
* @typedef {Object} ResInfo
* @property {String} code - 地区编码
* @property {String} name - 地区名称
* @property {Number} similarity - 相似度(完全匹配时为1)
* @property {Number} split_res_index - 对应的split_res数组中的数据的索引
* @property {String} [capture_province] - 捕获的省份内容,此字段只在省份信息内存在
* @property {String} [capture_city] - 捕获的城市内容,此字段只在城市信息内存在
* @property {String} [capture_county] - 捕获的区县内容,此字段只在区县信息内存在
* @property {Number} [max_city_split_res_index] - 最大相似度的城市对应的split_res数组中的数据的索引,此字段只在最终结果中存在
* @property {Number} [max_city_resInfo_index] - 最大相似度的城市对应的city_resInfo_list数组中的数据的索引,此字段只在最终结果中存在
* @property {Number} [max_province_split_res_index] - 最大相似度的省份对应的split_res数组中的数据的索引,此字段只在最终结果中存在
* @property {Number} [max_province_resInfo_index] - 最大相似度的省份对应的province_resInfo_list数组中的数据的索引,此字段只在最终结果中存在
*/
/**
* 储存匹配到的省份信息
* @type {ResInfo[]}
*/
let province_resInfo_list = []
/**
* 储存匹配到的城市信息
* @type {ResInfo[]}
*/
let city_resInfo_list = []
/**
* 储存匹配到的区县信息
* @type {ResInfo[]}
*/
let county_resInfo_list = []
/**
* 分割后的数据的扩展结构
* @typedef {Object} SplitResEx
* @property {String} value - 原始split_res数组内对应的元素
* @property {Number} type - 类型标记
*/
/**
* 对split_res数组的数据进行处理后的拓展数据
* @type {SplitResEx[]}
*/
let split_res_ex = split_res
.filter(split_res_item => split_res_item !== "")
.map(split_res_item => {
return {
value: split_res_item,
type: 0,
}
})
// 用于匹配11位手机号的正则表达式
let reg_exp_mobile = new RegExp("[0-9]{11}", "gmu")
// 储存手机的识别结果
let mobile = ""
// 储存split_res_ex数组内识别到手机的元素的索引
let mobile_split_res_index = -1
// 开始识别,遍历split_res_ex
for (let i = 0; i < split_res_ex.length; i++) {
let split_res_item = split_res_ex[i] // 当前遍历元素
// 识别到手机(如果有多个,只储存最后一个)
if (reg_exp_mobile.test(split_res_item.value)) {
split_res_item.type |= TYPE_MOBILE // 标记类型
mobile = split_res_item.value // 储存识别结果
mobile_split_res_index = i // 储存对应索引
}
// 对每个split_res_ex元素遍历识别所有的省份、城市、区县
// 构建[省份、城市、区县]遍历结构
let loop_data = [
{ data: provinces, type: TYPE_ADDR_PROVINCE, resInfo_list: province_resInfo_list, type_name: "province" },
{ data: citys, type: TYPE_ADDR_CITY, resInfo_list: city_resInfo_list, type_name: "city" },
{ data: countys, type: TYPE_ADDR_COUNTY, resInfo_list: county_resInfo_list, type_name: "county" },
]
// 遍历[省份、城市、区县]
for (let j = 0; j < 3; j++) {
// 遍历(省份)或(城市)或(区县)
for (let item of loop_data[j].data) {
let similarity = undefined // 相似度
let capture_value = undefined // 储存捕获到的名称
// 完整匹配某个(省份)或(城市)或(区县)的名称
if (split_res_item.value.search(item.name) !== -1) {
similarity = 1 // 相似度为1
capture_value = item.name // 储存完整名称
}
// 非完整匹配某个(省份)或(城市)或(区县)的名称
else if (split_res_item.value.search(item.name_except_dispensible) !== -1) {
similarity = item.similarity // 储存相似度(前面已计算)
capture_value = item.name_except_dispensible // 储存省略后的名称
}
// 成功匹配,储存信息
if (similarity !== undefined) {
loop_data[j].resInfo_list.push({
code: item.code,
name: item.name,
similarity: similarity,
split_res_index: i,
[`capture_${loop_data[j].type_name}`]: capture_value
})
}
}
}
}
// 由区县的匹配结果决定地址信息最终是否匹配成功
// 只要区县匹配成功,不论城市和省份是否匹配成功,最终都将按匹配成功处理
// 下面的处理主要是针对匹配到多个区县的情况,最终按叠加的相似度决定匹配结果
// 因为该步骤主要是为了消除误判的区县,所以区县所属的城市和省份被匹配时,权重分别是10倍和100倍
if (county_resInfo_list.length >= 1) {
// 遍历区县的匹配结果
for (let i = 0; i < county_resInfo_list.length; i++) {
let county_resInfo_item = county_resInfo_list[i] // 本次遍历的区县元素
let add_similarity = 0 // 最后要叠加到区县结果内的相似度
// 遍历城市的匹配结果
for (let j = 0; j < city_resInfo_list.length; j++) {
// 若匹配成功的区县其所属的城市同时也匹配成功,则记录其相似度
if (city_resInfo_list[j].code.substring(0, 4) === county_resInfo_item.code.substring(0, 4)) {
// 被匹配的区县所属的城市可能会匹配到多个,所以要找出其中相似度最大的
if (city_resInfo_list[j].similarity > add_similarity) {
add_similarity = city_resInfo_list[j].similarity
}
}
}
county_resInfo_item.similarity += add_similarity * 10 // 在城市的相似度的基础上乘10
// 遍历省份的匹配结果(同上)
add_similarity = 0
for (let j = 0; j < province_resInfo_list.length; j++) {
if (province_resInfo_list[j].code.substring(0, 2) === county_resInfo_item.code.substring(0, 2)) {
if (province_resInfo_list[j].similarity > add_similarity) {
add_similarity = province_resInfo_list[j].similarity
}
}
}
county_resInfo_item.similarity += add_similarity * 100 // 在省份的相似度的基础上乘10
}
// 按叠加后的相似度对区县的匹配结果进行排序,从大到小
county_resInfo_list.sort((item0, item1) => item1.similarity - item0.similarity)
// 排序后的区县匹配结果中的第一个元素视作最终匹配元素
let matching_county = county_resInfo_list[0]
// 在对应的split_res_ex数组内的数据上加上区县地址匹配标记
split_res_ex[matching_county.split_res_index].type |= TYPE_ADDR_COUNTY
// 在城市匹配结果中寻找最终匹配的区县所属的城市
let max_similarity = 0 // 临时变量,记录当前已遍历的匹配城市中相似度最大的
let max_resInfo_index = -1 // 相似度最大的城市在city_resInfo_list数组中对应的索引
for (let i = 0; i < city_resInfo_list.length; i++) {
if (city_resInfo_list[i].code.substring(0, 4) === matching_county.code.substring(0, 4)) {
if (city_resInfo_list[i].similarity > max_similarity) {
max_similarity = city_resInfo_list[i].similarity
max_resInfo_index = i
}
}
}
// 若寻找到相应的匹配城市,则储存和设置对应的信息
if (max_resInfo_index !== -1) {
matching_county.max_city_split_res_index = city_resInfo_list[max_resInfo_index].split_res_index
matching_county.max_city_resInfo_index = max_resInfo_index
split_res_ex[city_resInfo_list[max_resInfo_index].split_res_index].type |= TYPE_ADDR_CITY
}
// 在省份匹配结果中寻找最终匹配的区县所属的省份,同上
max_similarity = 0
max_resInfo_index = -1
for (let i = 0; i < province_resInfo_list.length; i++) {
if (province_resInfo_list[i].code.substring(0, 2) === matching_county.code.substring(0, 2)) {
if (province_resInfo_list[i].similarity > max_similarity) {
max_similarity = province_resInfo_list[i].similarity
max_resInfo_index = i
}
}
}
if (max_resInfo_index !== -1) {
matching_county.max_province_split_res_index = province_resInfo_list[max_resInfo_index].split_res_index
matching_county.max_province_resInfo_index = max_resInfo_index
split_res_ex[province_resInfo_list[max_resInfo_index].split_res_index].type |= TYPE_ADDR_PROVINCE
}
}
// 储存名字的识别结果
let name = ""
// split_res_ex数组中还未匹配到任何类型的元素
let split_res_type_equal_0 = []
// 遍历split_res_ex数组,寻找还未匹配到任何类型的元素
for (let i =0; i < split_res_ex.length; i++) {
if (split_res_ex[i].type === 0) {
split_res_type_equal_0.push({
split_res_item: split_res_ex[i],
index: i
})
}
}
// 按内容的长度排序,从小到大
split_res_type_equal_0.sort((item0, item1) =>
item0.split_res_item.value.length - item1.split_res_item.value.length
)
// 遍历排序后的split_res_type_equal_0数组(split_res_type_equal_0数组中除了可能存在名字外,还可能存在"详细地址")
// 规则1:名字不会被除手机外的其他信息包裹在中间,既除手机外,名字应该在两端
// 规则2:名字不会比"详细地址"长
for (let i = 0; i < split_res_type_equal_0.length; i++) {
let item = split_res_type_equal_0[i].split_res_item // 对应的split_res_item数组的元素
let index = split_res_type_equal_0[i].index // 对应的split_res_item数组的元素的索引
let access_indexs; // 储存特定情况下,名字所有可能出现的位置(名字应该在两端)
// 若未匹配到手机,则名字应该在两端,否则,名字应该在除了手机所在位置后的两端
if (mobile_split_res_index === 0) {
access_indexs = [1, split_res_ex.length - 1]
}
else if (mobile_split_res_index === split_res_ex.length - 1) {
access_indexs = [0, split_res_ex.length - 2]
}
else {
access_indexs = [0, split_res_ex.length - 1]
}
// 匹配
if (access_indexs.indexOf(index) !== -1) {
// 若split_res_type_equal_0内不止一个元素,说明split_res_type_equal_0内存在"详细地址"部分
if (split_res_type_equal_0.length > 1) {
let add_length = 0 // 储存除本元素外的其他元素的内容长度的累加值
// 累加其他部分
for (let j = 0; j < i; j++) {
add_length += split_res_type_equal_0[j].split_res_item.value.length
}
for (let j = i + 1; j < split_res_type_equal_0.length; j++) {
add_length += split_res_type_equal_0[j].split_res_item.value.length
}
// 若本元素长度小于其他元素的长度累加值,则判定本元素为名字
if (item.value.length < add_length) {
item.type |= TYPE_NAME
name = item.value
break
}
}
// 若split_res_type_equal_0内只有一个元素,则判定本元素为名字
else{
item.type |= TYPE_NAME
name = item.value
break
}
}
}
let province = "" // 储存省份的识别结果
let city = "" // 储存城市的识别结果
let county = "" // 储存区县的识别结果
let code = "" // 储存地区编码的识别结果
let detail = "" // 储存详细地址的识别结果
// 若有识别到区县地址
if (county_resInfo_list.length > 0) {
let matching_county = county_resInfo_list[0] // 最终匹配元素
let detail_join_index_list = [] // 储存详细地址的各个部分对应的split_res_ex数组元素的索引
// 若有匹配到的省份
if (matching_county.hasOwnProperty("max_province_split_res_index")) {
detail_join_index_list.push(matching_county.max_province_split_res_index)
province = province_resInfo_list[matching_county.max_province_resInfo_index].name
}
else {
province = areaList.province_list[matching_county.code.substring(0, 2) + "0000"]
}
// 若有匹配到的城市
if (matching_county.hasOwnProperty("max_city_split_res_index")) {
// 检测是否与匹配到的省份对应的split_res_ex数组元素的索引重复,不重复才添加
if (detail_join_index_list.indexOf(matching_county.max_city_split_res_index) === -1) {
detail_join_index_list.push(matching_county.max_city_split_res_index)
}
city = city_resInfo_list[matching_county.max_city_resInfo_index].name
}
else {
city = areaList.city_list[matching_county.code.substring(0, 4) + "00"]
}
// 检测是否与匹配到的省份及城市对应的split_res_ex数组元素的索引重复,不重复才添加
if (detail_join_index_list.indexOf(matching_county.split_res_index) === -1) {
detail_join_index_list.push(matching_county.split_res_index)
}
county = matching_county.name
code = matching_county.code
// 将其余未匹配到任何类型的元素判定为"详细地址"部分,添加其对应的split_res_ex数组元素的索引到detail_join_index_list数组
for (let i = 0; i < split_res_ex.length; i++) {
if (split_res_ex[i].type === 0) {
detail_join_index_list.push(i)
}
}
// 拼接detail_join_index_list数组内所有元素对应的split_res_ex数组元素的内容
detail = detail_join_index_list.map(i => split_res_ex[i].value).join("")
// 去除省份信息
if (matching_county.hasOwnProperty("max_province_resInfo_index")) {
detail = detail.replace(province_resInfo_list[matching_county.max_province_resInfo_index].capture_province, "")
}
// 去除城市信息
if (matching_county.hasOwnProperty("max_city_resInfo_index")) {
detail = detail.replace(city_resInfo_list[matching_county.max_city_resInfo_index].capture_city, "")
}
// 去除区县信息
detail = detail.replace(matching_county.capture_county, "")
}
return {
name: name,
tel: mobile,
province: province,
city: city,
county: county,
areaCode: code,
addressDetail: detail,
}
}
页面更新:2024-05-10
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号