Java 利用正则表达式完美解析全国省市区地址
一、问题场景描述
最近在项目中遇到了一个全国地址解析的一个场景,前端会传来一个字符串,后端需自动解析出 xx省xx市xx区+详细地址
的这种格式。
因为我们的数据来源于其他系统,客户地址在其他系统可能是随便填的,并不是正确的,所以前端也做了支持更改地址的操作。所以,我们的地址解析方式也是根据前端的地址格式来进行解析的。
二、解决方案
我也是第一次遇到这个场景,于是首先百度了一手,得到的解决方案有:
- 根据正则表达式进行解析;
- 字符串匹配遍历的方式;
tips: 还有其他的解决方案,已经找不到网址了,就不贴了
根据我们的这个业务需求,用正则是比较方便的,因为我们前端会有地址的固定格式,比如:江苏省南京市雨花台区某某地址,对于这段字符串,只要成功匹配出省、市、区就可以完成地址的解析。
三、开发过程中遇到的问题
我一开始是直接用了百度的正则,这个正则表达式,可以解析出正常的省市区地址,但是对于北京市这种直辖市和香港行政区这些地方没有做很好的匹配。于是,根据前端的地址选项做出了正则的更改。
前端的地址选项格式:
前端对于北京上海这类直辖市,的格式:北京市北京市西城区xx地址
// 百度到的正则
String regex="(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<village>.*)";
// 修改后的正则
String regex = "(?<province>[^省]+省|.+自治区|[^澳门]+澳门|[^香港]+香港|[^市]+市)?(?<city>[^自治州]+自治州|[^特别行政区]+特别行政区|[^市]+市|.*?地区|.*?行政单位|.+盟|市辖区|[^县]+县)(?<county>[^县]+县|[^市]+市|[^镇]+镇|[^区]+区|[^乡]+乡|.+场|.+旗|.+海域|.+岛)?(?<address>.*)";
四、应用代码
1、地址封装类
@Data
@NoArgsConstructor
public class WSSsdrAddress implements Serializable {
private String province;
private String city;
private String county;
private String address;
public WSSsdrAddress(String province, String city, String county, String address) {
if (StringUtils.isBlank(province) ||
StringUtils.isBlank(city) ||
StringUtils.isBlank(county) ||
StringUtils.isBlank(address)) {
throw new BaseException("客户联系地址出错");
}
this.province = province;
this.city = city;
this.county = county;
this.address = address;
}
}
2、地址解析工具类
public class AddressUtil {
private AddressUtil() {}
/**
* 从地址串中解析提取出省市区等信息
* @param address 地址信息
* @return 解析后的地址Map
*/
private static Map<String,String> addressResolution(String address){
//1.地址的正则表达式
String regex = "(?<province>[^省]+省|.+自治区|[^澳门]+澳门|[^香港]+香港|[^市]+市)?(?<city>[^自治州]+自治州|[^特别行政区]+特别行政区|[^市]+市|.*?地区|.*?行政单位|.+盟|市辖区|[^县]+县)(?<county>[^县]+县|[^市]+市|[^镇]+镇|[^区]+区|[^乡]+乡|.+场|.+旗|.+海域|.+岛)?(?<address>.*)";
//2、创建匹配规则
Matcher m = Pattern.compile(regex).matcher(address);
String province;
String city;
String county;
String detailAddress;
Map<String,String> map = new HashMap<>(16);
while (m.find()){
//加入省
province = m.group("province");
map.put("province", province == null ? "" : province.trim());
//加入市
city = m.group("city");
map.put("city", city == null ? "" : city.trim());
//加入区
county = m.group("county");
map.put("county", county == null ? "" : county.trim());
//详细地址
detailAddress = m.group("address");
map.put("address", detailAddress == null ? "" : detailAddress.trim());
}
return map;
}
/**
* 根据地址获取解析后的地址对象
* @param address 解析前地址Str
* @return 解析后地址对象
*/
public static WSSsdrAddress resolveAddress(String address) {
if (CharSequenceUtil.isBlank(address)) {
throw new BaseException("客户联系地址出错");
}
Map<String, String> addressMap = addressResolution(address);
return new WSSsdrAddress(addressMap.get("province"), addressMap.get("city"), addressMap.get("county"), addressMap.get("address"));
}
}
3、测试结果
下面的测试应该包含了全国90%以上稀奇古怪的区域名了:
五、附件
我们的项目是搭配着前端提供的省市区进行解析的,在此附上前端使用的全国省市区json:https://github.com/getActivity/ProvinceJson/blob/master/province.json
如果帮助到了你,或者觉得有用,不妨点个赞?
参考文章: