ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java地址解析库 address-parse 实测:把乱成一团的发货信息拆成姓名、手机、省市区,5个问答说清楚

Java地址解析库 address-parse 实测:把乱成一团的发货信息拆成姓名、手机、省市区,5个问答说清楚 Java地址解析库 address-parse 实测把乱成一团的发货信息拆成姓名、手机、省市区5个问答说清楚【免费下载链接】address-parseJava 版智能解析收货地址项目地址: https://gitcode.com/gh_mirrors/addr/address-parse做二手闲置平台的你大概见过这种订单备注「广东省深圳市龙岗区南湾街道尚峰花园4C2231 13111111111 谢先生」。一个文本框里姓名、电话、省市区、门牌号全糊在一起。今天要聊的 Java 地址解析库 address-parse就是专门收拾这类烂摊子的——它把一段乱字拆成结构化字段全程本地运行一行代码入口。先交代一下背景。我负责的二手交易平台有个环节买家下单后卖家要填发货地址但很多卖家直接把地址、电话、名字连成一句话丢进来。平台要拿它去生成寄件单必须拆出联系人、手机号和规范的省市区。最初我们打算自己写正则三个月后放弃了——不是写不出来是永远有写不完的边界情况。下面这 5 个问答记录了我从踩坑到接完这套方案的全过程每一问都对应一个你一定会碰到的实际问题。第一个问题手写正则拆地址为什么总是拆不干净先给你看看当初让我们崩溃的三类输入带标签的「收货人: 杨燕艳 / 手机号码: 13111111111 / 所在地区: 广东省深圳市龙岗区龙岗街道」带国际前缀和空格号的「何花菊86-13311111111辽宁省盘锦市盘山县东郭镇」带座机加邮编的「湛江市廉江市车板镇人才市场0755-22107333.曹建林 邮编713200」手写正则处理它们等于不断打补丁要去「收货人」「联系电话」这些标签词要兼容全角逗号、换行、分号还要识别86-前缀、131 1111 1111这种带空格号码、0755-22107333这种座机。每加一种情况正则就长一截最后变成一坨没人敢动的代码。address-parse 的处理顺序很聪明它把这件事拆成流水线先清洗再剥离联系方式最后才做行政区划识别。清洗阶段直接剥掉「收货人」「详细地址」「所在地区」「手机号码」等一批关键词再抹掉特殊符号然后把手机号、座机号、邮编逐个正则抠出来从原文里删掉剩下的文字里再找省市区。源码在 AddressParse.java 的cleanAddress方法里可排除关键词是一份常量列表EXCLUDE_KEYS你甚至可以往里面加自己平台特有的词。第二个问题不联网、不上云它凭什么认得出省市区这是我最好奇的一点。看了源码才明白秘密在 classpath 里的行政区划数据文件china-area.json以及它启动时构建的一棵省→市→区三级树。类加载时AddressParse的静态代码块程序读取这份 JSON经过TreeUtils拼装成带父子关系的树分别得到省级列表、市级列表、区级列表全量常驻内存。之后每次解析就是在这三张表里做匹配完全离线没有一次网络请求。这也是它敢说数据安全的原因——你的地址数据不会离开自己的服务器。匹配策略比我想象的还要多一道保险它同时跑三种从省名正向往下推省→市→区从市名逆向定位先认市再倒推省从区/县名逆向定位先认区再倒推省市所以同一段地址经常能命中多个层级parse方法返回的是一个ListParseResult每个结果用type字段标注它命中到哪一级AreaEnum里的PROVINCE、CITY、DISTRICT。看 README 里的实测输出会更直观比如这条太阳鲜鲜 盐田区山海四季城F栋17A13111111111 姓名太阳鲜鲜电话手机13111111111省广东省市深圳市区盐田区详细地址山海四季城F栋17A类型AREA名字在开头、地址在中间、手机在结尾照样一次拆全。而且结果里带zipCode邮编和区划代码可以直接拿去对接快递接口。第三个问题名字和手机号粘在一起怎么分得开「袁月青13111111111四川省成都市高新西区百叶路1号电子科技大学成都学院」这种写法名字、号码、地址之间一个空格都没有正则基本无解。address-parse 用了另一招按空格把剩余文本切段取加权长度最短的那段当姓名。理由很朴素——地址通常比人名长。它的length()方法把汉字按两位、英文按一位加权避免纯字符数把长名字误判。号码这块它也处理得够全131 1111 1111这类带空格的手机号会在清洗阶段被重新拼回去86-13311111111这种国际前缀单独有正则兜底。另外它还会顺带把邮编6 位数字识别出来放进zipCode字段。有一个新手必踩的坑要提醒你别把parse返回的多个结果直接当重复数据丢弃。同样是「深圳市南山区南光路龙坤居2栋D座714收件人张珍云」CITY级和AREA级结果都可能出现区级通常最准。我写了这样一个选择器保证只留最完整的那条public static ParseResult pickBest(ListParseResult results) { if (CollectionUtils.isEmpty(results)) { return null; } return results.stream() .sorted(Comparator.comparingInt(r - rank(r.getType()))) .findFirst() .orElse(results.get(0)); } // 优先级区 市 省 private static int rank(AreaEnum type) { if (type AreaEnum.DISTRICT) return 0; if (type AreaEnum.CITY) return 1; return 2; }第四个问题接进一个老项目总共要动几行代码答案是一个依赖 一个方法调用。这个库的对外 API 收敛得极简核心就是com.neo.address.parse.AddressParse下的静态方法parse(String)传入原文拿回ListParseResult。pom 里加好依赖Guava、Hutool、Apache Commons、Gson、LombokJDK 8 即可然后像我这样包一层业务代码就完全不用感知细节public class ShipInfoExtractor { /** * 把卖家填写的原始发货信息拆成结构化字段 */ public static ParseResult extract(String rawText) { ListParseResult results AddressParse.parse(rawText); return pickBest(results); } }调用方拿到的是一个字段齐全的对象ParseResult的字段清单如下字段含义示例name联系人姓名谢先生mobile手机号含 86 前缀13111111111phone座机号0755-22107333province / city / area省 / 市 / 区广东省 / 深圳市 / 龙岗区detail详细地址南湾街道尚峰花园4C2231zipCode邮编713200type命中层级AREA对象还自带format()方法能直接输出「姓名…手机…省…」这样一行日志排查问题非常方便。核心结果类在 ParseResult.java想看完整的真实案例直接翻测试类 AddressParseTest.java里面躺着 44 条真实脏地址样本覆盖上面讲的所有刁钻情况。第五个问题几万条历史数据要洗一遍扛得住吗我们上线前最担心的就是性能。实测数据是这样类加载初始化一次性耗时约 440 毫秒建树、载入区划数据之后 README 里 44 条脏地址整批跑完约 112 毫秒平均单条约 2 到 3 毫秒。这个量级洗几万条历史数据也就几分钟的事。三个提效要点亲测有效预热应用启动时主动调一次parse让静态代码块提前把区划树建好避免第一个请求吃初始化时间。批量并行区划数据只读PROVINCE_LIST、CITY_LIST、AREA_LIST是静态只读列表并行流安全。我直接用parallelStream批量清洗ListParseResult cleaned historyOrders.stream() .map(ShipInfoExtractor::extract) .filter(r - StringUtils.isNotBlank(r.getMobile()) || StringUtils.isNotBlank(r.getPhone())) .collect(Collectors.toList());失败兜底解析失败返回空时记录日志进人工复核队列而不是静默丢弃。毕竟是历史数据宁可慢一点也要留痕。上线前最后过一遍的避坑清单这几条是我们踩完坑总结的你直接拿去用返回多结果时不要取第一个按type排序选区级最稳地址只有「xx路xx号」没有省市区时city可能为空这是正常兜底别当解析失败「黔南布依族苗族自治州」「大兴安岭地区」这类长名称会正常匹配别在业务里截断全角标点、换行、Tab 交给库清洗就好别在外面再叠一层正则容易互相干扰需要自定义过滤词时往AddressParse.EXCLUDE_KEYS里加不用改源码逻辑下一步把它跑起来这套方案的完整源码和测试样例都在仓库里动手最快的方式克隆项目git clone https://gitcode.com/gh_mirrors/addr/address-parse直接运行测试主类AddressParseTest先看 44 条真实地址的解析输出把测试数据换成你自己平台积压的订单备注跑一遍看命中率满意了再把ShipInfoExtractor这层包装挪进你的服务里从写不完的正则到一行调用拆全字段中间差的不是一个更长的表达式而是一棵离线区划树加一套分级匹配策略。如果你的业务里也有任何一段文字里混着人、电话、地址的场景——收货地址、发货地址、报名信息、预约记录——都值得把它拉下来试试。【免费下载链接】address-parseJava 版智能解析收货地址项目地址: https://gitcode.com/gh_mirrors/addr/address-parse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表