
Java解析不规范中国区域地址本文用于解析将收集的中国行政区域地址转成规范标准行政区域,可支持解析一下各种复杂不规范的字符串, 目前只支持到省市区(县)三级江西省赣州市寻乌县江西省赣州市寻乌江西省赣州寻乌江西赣州寻乌县江西-赣州-寻乌县江西/赣州/寻乌江西省/赣州市/寻乌县…获取标准中国行政区域库博主数据库中已有标准数据, 故不介绍如何获取(可通过网洛来源获取)ListRecordareaListDb.find(Db.getSqlPara(com.dsfa.teas.lgydx.web.enroll.enrollunit.sql.unit.getArea));#sql(getArea)selectname,areacode,treeinfo_level,treeinfo_pid,aliasfromdsfa_areawheretreeinfo_levelin(2,3,4)andds_deleted0#end定义需要用的实体类RegionData public class Region { /** 国标编码 */ private String code; /** 标准全称 */ private String name; /** 别名列表从alias字符串切割 */ private ListString aliasList; /** 级别1省2市3区县 */ private Integer level; /** 父编码 */ private String parentCode; }AreaDTOData public class AreaDTO { private String provinceCode; private String province; private String cityCode; private String city; private String countyCode; private String county; /** * 获取拼接全称路径格式 xx/xx/xx缺后面层级自动截断 * return 如 江西省/赣州市/寻乌县或 江西省/赣州市或 江西省 */ public String getFullPath() { ListString parts new ArrayList(); if (StrKit.isNotBlank(province)) { parts.add(province); } if (StrKit.isNotBlank(city)) { parts.add(city); } if (StrKit.isNotBlank(county)) { parts.add(county); } return String.join(/, parts); } }将标准地址库解析成Region存入内存中, 方便后续取用这里定义了可能存在的区域后缀, 或许还存在没考虑到的, 后缀越全面后续分词匹配越精准, 如遇到无法解析的地址可以进行维护后缀// 内存缓存 privateListRegionprovinceList;privateListRegioncityList;privateListRegioncountyList;publicvoidloadRegionCache(){ListRecordareaListDb.find(Db.getSqlPara(com.dsfa.teas.lgydx.web.enroll.enrollunit.sql.unit.getArea));ListRegionallRegionnewLinkedList();ListStringsuffixesArrays.asList(newString[]{特别行政区,自治州,自治县,自治区,林区,地区,盟,省,市,县,区,旗,乡,镇});// 切割别名字符串为Listfor(Recordr:areaList){RegionregionnewRegion();region.setName(r.getStr(name));region.setCode(r.getStr(areacode));region.setLevel(Integer.parseInt(r.getStr(treeinfo_level)));region.setParentCode(r.getStr(treeinfo_pid));if(StrKit.isNotBlank(r.getStr(alias))){ListStringaliasArrays.stream(r.getStr(alias).split(,)).map(String::trim).filter(StrKit::isNotBlank).collect(Collectors.toList());// 正式名称去掉后缀 模拟不规范的写法ListStringaddsuffixes.stream().filter(suffix-r.getStr(name).endsWith(suffix)).map(suffix-r.getStr(name).replace(suffix,)).collect(Collectors.toList());alias.addAll(add);region.setAliasList(alias);}else{region.setAliasList(Collections.singletonList(r.getStr(name)));}// 关键对别名按名称长度降序排序, 防止短词提前匹配region.getAliasList().sort(Comparator.comparingInt(String::length).reversed());allRegion.add(region);}// 按级别分组provinceListallRegion.stream().filter(r-r.getLevel()2).collect(Collectors.toList());cityListallRegion.stream().filter(r-r.getLevel()3).collect(Collectors.toList());countyListallRegion.stream().filter(r-r.getLevel()4).collect(Collectors.toList());// 关键按名称长度降序排序长名称优先匹配防止短词提前匹配provinceList.sort((o1,o2)-Integer.compare(o2.getName().length(),o1.getName().length()));cityList.sort((o1,o2)-Integer.compare(o2.getName().length(),o1.getName().length()));countyList.sort((o1,o2)-Integer.compare(o2.getName().length(),o1.getName().length()));System.out.println( 行政区划缓存加载完成 );System.out.printf(省%d 条市%d 条区县%d 条%n,provinceList.size(),cityList.size(),countyList.size());}使用ApplicationRunner, 让项目启动时就预先加载好标准区域库ComponentpublicclassRegionCacheLoaderimplementsApplicationRunner,PriorityOrdered{ResourceprivateRegionParseCacheUtilregionParseCacheUtil;Overridepublicvoidrun(ApplicationArgumentsargs)throwsException{// 这里执行加载区划缓存regionParseCacheUtil.loadRegionCache();}OverridepublicintgetOrder(){returnInteger.MAX_VALUE;}}地址解析入口方法/** * 地址解析入口 * param rawAddr 原始地址 支持江西省赣州市寻乌县 / 江西赣州寻乌 / 江西/赣州/寻乌 * return AreaDTO */publicAreaDTOparse(StringrawAddr){if(StrKit.isBlank(rawAddr)){returnnull;}AreaDTOdtonewAreaDTO();// 预处理移除 / 和所有空白字符StringremainrawAddr.replace(/,).replace(/,).replaceAll(\\s,);// 匹配省for(Regionp:provinceList){for(Stringalias:p.getAliasList()){if(remain.startsWith(alias)){dto.setProvince(p.getName());dto.setProvinceCode(p.getCode());remainremain.substring(alias.length());break;}}if(dto.getProvince()!null)break;}// 匹配市只有匹配到省之后才继续if(dto.getProvince()!null){// 只在本省内的市做匹配ListRegiontempCityListcityList.stream().filter(city-dto.getProvinceCode().equals(city.getParentCode())).collect(Collectors.toList());for(Regionc:tempCityList){for(Stringalias:c.getAliasList()){if(remain.startsWith(alias)){dto.setCity(c.getName());dto.setCityCode(c.getCode());remainremain.substring(alias.length());break;}}if(dto.getCity()!null)break;}}// 匹配区县匹配到市后继续if(dto.getCity()!null){// 只在本市内的区县做匹配ListRegiontempCountryListcountyList.stream().filter(county-dto.getCityCode().equals(county.getParentCode())).collect(Collectors.toList());for(Regionco:tempCountryList){for(Stringalias:co.getAliasList()){if(remain.startsWith(alias)){dto.setCounty(co.getName());dto.setCountyCode(co.getCode());break;}}if(dto.getCounty()!null)break;}}returndto;}使用实例AreaDTOparseregionParseCacheUtil.parse(area);StringfullPathparse.getFullPath();System.out.println(解析后的标准行政区域 fullPath);AreaDTO 存有省市区-区域编码code, 有需要可以使用