☰
Java解析不规范中国区域地址
2026/10/31 10:57:19 网站建设 项目流程

Java解析不规范中国区域地址

本文用于解析将收集的中国行政区域地址转成规范标准行政区域,可支持解析一下各种复杂不规范的字符串, 目前只支持到省市区(县)三级

江西省赣州市寻乌县
江西省赣州市寻乌
江西省赣州寻乌
江西赣州寻乌县
江西-赣州-寻乌县
江西/赣州/寻乌
江西省/赣州市/寻乌县…

  1. 获取标准中国行政区域库
    博主数据库中已有标准数据, 故不介绍如何获取(可通过网洛来源获取)
List<Record>areaList=Db.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_deleted='0'#end
  1. 定义需要用的实体类
    Region
@Data public class Region { /** 国标编码 */ private String code; /** 标准全称 */ private String name; /** 别名列表(从alias字符串切割) */ private List<String> aliasList; /** 级别:1省,2市,3区县 */ private Integer level; /** 父编码 */ private String parentCode; }

AreaDTO

@Data 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() { List<String> 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); } }
  1. 将标准地址库解析成Region存入内存中, 方便后续取用

这里定义了可能存在的区域后缀, 或许还存在没考虑到的, 后缀越全面后续分词匹配越精准, 如遇到无法解析的地址可以进行维护后缀

// ====================== 内存缓存 ======================privateList<Region>provinceList;privateList<Region>cityList;privateList<Region>countyList;publicvoidloadRegionCache(){List<Record>areaList=Db.find(Db.getSqlPara("com.dsfa.teas.lgydx.web.enroll.enrollunit.sql.unit.getArea"));List<Region>allRegion=newLinkedList<>();List<String>suffixes=Arrays.asList(newString[]{"特别行政区","自治州","自治县","自治区","林区","地区","盟","省","市","县","区","旗","乡","镇"});// 切割别名字符串为Listfor(Recordr:areaList){Regionregion=newRegion();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"))){List<String>alias=Arrays.stream(r.getStr("alias").split(",")).map(String::trim).filter(StrKit::isNotBlank).collect(Collectors.toList());// 正式名称去掉后缀 模拟不规范的写法List<String>add=suffixes.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);}// 按级别分组provinceList=allRegion.stream().filter(r->r.getLevel()==2).collect(Collectors.toList());cityList=allRegion.stream().filter(r->r.getLevel()==3).collect(Collectors.toList());countyList=allRegion.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());}
  1. 使用ApplicationRunner, 让项目启动时就预先加载好标准区域库
@ComponentpublicclassRegionCacheLoaderimplementsApplicationRunner,PriorityOrdered{@ResourceprivateRegionParseCacheUtilregionParseCacheUtil;@Overridepublicvoidrun(ApplicationArgumentsargs)throwsException{// 这里执行加载区划缓存regionParseCacheUtil.loadRegionCache();}@OverridepublicintgetOrder(){returnInteger.MAX_VALUE;}}
  1. 地址解析入口方法
/** * 地址解析入口 * @param rawAddr 原始地址 支持:江西省赣州市寻乌县 / 江西赣州寻乌 / 江西/赣州/寻乌 * @return AreaDTO */publicAreaDTOparse(StringrawAddr){if(StrKit.isBlank(rawAddr)){returnnull;}AreaDTOdto=newAreaDTO();// 预处理:移除 / 和所有空白字符Stringremain=rawAddr.replace("/","").replace("/","").replaceAll("\\s+","");// 匹配省for(Regionp:provinceList){for(Stringalias:p.getAliasList()){if(remain.startsWith(alias)){dto.setProvince(p.getName());dto.setProvinceCode(p.getCode());remain=remain.substring(alias.length());break;}}if(dto.getProvince()!=null)break;}// 匹配市(只有匹配到省之后才继续)if(dto.getProvince()!=null){// 只在本省内的市做匹配List<Region>tempCityList=cityList.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());remain=remain.substring(alias.length());break;}}if(dto.getCity()!=null)break;}}// 匹配区县(匹配到市后继续)if(dto.getCity()!=null){// 只在本市内的区县做匹配List<Region>tempCountryList=countyList.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;}
  1. 使用实例
AreaDTOparse=regionParseCacheUtil.parse(area);StringfullPath=parse.getFullPath();System.out.println("解析后的标准行政区域 = "+fullPath);

AreaDTO 存有省市区-区域编码code, 有需要可以使用

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询