推荐一款免费的收货信息智能识别工具

大家好,我是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

标签:遍历   信息   收货   数组   字段   区县   省份   索引   元素   智能   工具   数据   城市

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top