BE_ParseAddress.groovy 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. import com.sweetfish.service.RetResult
  2. import com.sdtool.common.api.BusinessExecutor
  3. import com.sdtool.common.datas.ERPModule
  4. import com.sdtool.common.entity.base.ProcessStringItem
  5. import com.sdtool.common.entity.system.ParseAreaResult
  6. import com.sdtool.common.tool.ERPUtils
  7. import groovy.json.JsonSlurper
  8. import org.apache.commons.lang3.StringUtils
  9. import org.apache.logging.log4j.LogManager
  10. import org.apache.logging.log4j.Logger
  11. import javax.annotation.Resource
  12. import java.util.concurrent.atomic.AtomicInteger
  13. import java.util.concurrent.atomic.AtomicReference
  14. import java.util.regex.Matcher
  15. import java.util.regex.Pattern
  16. import java.util.stream.Collectors
  17. import java.util.stream.Stream
  18. /**
  19. * Created by jlutt on 2022-02-09
  20. * 地址解析为省市区联系人电话
  21. * @author jlutt
  22. */
  23. class BE_ParseAddress implements BusinessExecutor<ProcessStringItem, ParseAreaResult> {
  24. protected final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
  25. private static final String EMPTY = "", BLANK = " "
  26. /**
  27. * 手机号正则
  28. */
  29. public static String mobile = "(86-1[0-9]{10})|(861[0-9]{10})|(1[0-9]{10})|(1[0-9]{2} [0-9]{4} [0-9]{4})|(1[0-9]{6} [0-9]{4})|(1[0-9]{6}-[0-9]{4})"
  30. public static Pattern mobilePattern = Pattern.compile(mobile, 32)
  31. /**
  32. * 座机号正则
  33. */
  34. public static String phone = "(([0-9]{3,4}-)[0-9]{7,8})|([0-9]{12})|([0-9]{11})|([0-9]{10})|([0-9]{9})|([0-9]{8})|([0-9]{7})"
  35. public static Pattern phonePattern = Pattern.compile(phone, 32)
  36. /**
  37. * 邮编正则
  38. */
  39. public static String zipCode = "([0-9]{6})"
  40. public static Pattern zipCodePattern = Pattern.compile(zipCode, 32)
  41. def excludeKeys = [
  42. "自治区直辖县级行政区划",
  43. "省直辖县级行政区划",
  44. "联系人手机号码",
  45. "不代收货款",
  46. "所在地区",
  47. "详细地址",
  48. "收货地址",
  49. "手机号码",
  50. "发件人",
  51. "手机号",
  52. "收货人",
  53. "收件人",
  54. "不代收",
  55. "收货",
  56. "邮编",
  57. "电話",
  58. "电话",
  59. "地址",
  60. ":",
  61. ":",
  62. ";", ";", ",", ",", "。", "、"
  63. ]
  64. //省份有些简称,搜索省份时,可以去掉下面这些词再搜索一次,比如内蒙古自治区,可能简称为内蒙
  65. public Set<String> provinceKeys = new LinkedHashSet<>(Arrays.asList("特别行政区", "古自治区", "维吾尔自治区", "壮族自治区", "回族自治区", "自治区", "省省直辖", "省", "市"))
  66. public Set<String> cityKeys = new LinkedHashSet<>(Arrays.asList("布依族苗族自治州", "苗族侗族自治州", "藏族羌族自治州", "哈尼族彝族自治州", "壮族苗族自治州", "傣族景颇族自治州", "蒙古族藏族自治州",
  67. "傣族自治州", "白族自治州", "藏族自治州", "彝族自治州", "回族自治州", "蒙古自治州", "朝鲜族自治州", "地区", "哈萨克自治州", "盟", "市"))
  68. public Set<String> countyKeys = new LinkedHashSet<>(Arrays.asList("满族自治县", "满族蒙古族自治县", "蒙古族自治县", "朝鲜族自治县",
  69. "回族彝族自治县", "彝族回族苗族自治县", "彝族苗族自治县", "土家族苗族自治县", "布依族苗族自治县", "苗族布依族自治县",
  70. "彝族傣族自治县", "傣族彝族自治县", "仡佬族苗族自治县", "黎族苗族自治县", "苗族侗族自治县", "哈尼族彝族傣族自治县", "哈尼族彝族自治县",
  71. "彝族哈尼族拉祜族自治县", "傣族拉祜族佤族自治县", "傣族佤族自治县", "拉祜族佤族布朗族傣族自治县", "苗族瑶族傣族自治县", "彝族回族自治县",
  72. "独龙族怒族自治县", "保安族东乡族撒拉族自治县", "回族土族自治县", "撒拉族自治县", "哈萨克自治县", "塔吉克自治县",
  73. "回族自治县", "畲族自治县", "土家族自治县", "布依族自治县", "苗族自治县", "瑶族自治县", "侗族自治县", "水族自治县", "傈僳族自治县",
  74. "仫佬族自治县", "毛南族自治县", "黎族自治县", "羌族自治县", "彝族自治县", "藏族自治县", "纳西族自治县", "裕固族自治县", "哈萨克族自治县",
  75. "哈尼族自治县", "拉祜族自治县", "佤族自治县",
  76. "回族",
  77. "左旗", "右旗", "中旗", "后旗", "联合旗", "自治旗", "旗", "自治县",
  78. "区", "县", "市"))
  79. private Map<String, String> provinceShort = new LinkedHashMap<>()
  80. private Map<String, String> cityShort = new LinkedHashMap<>()
  81. private Map<String, String> countyShort = new LinkedHashMap<>()
  82. private Map<String, String> PROVINCES = new LinkedHashMap<String, String>()
  83. private Map<String, String> CITIES = new LinkedHashMap<String, String>()
  84. private Map<String, String> COUNTIES = new LinkedHashMap<String, String>()
  85. @Resource(name = "APP_HOME")
  86. private String appHome
  87. @Override
  88. String scriptName() {
  89. return "地址解析为省市区联系人电话"
  90. }
  91. @Override
  92. ERPModule module() {
  93. return ERPModule.ADDRESSPARSER
  94. }
  95. @Override
  96. void start(long supplierCode) {
  97. def jsonSlurper = new JsonSlurper()
  98. def provicesJsonFile = new File(appHome + File.separator + "conf" + File.separator + "addressdata" + File.separator + "provices.json")
  99. def provicesJsonArray = jsonSlurper.parse(provicesJsonFile)
  100. provicesJsonArray.each { it ->
  101. PROVINCES.put(it["code"] as String, it["name"] as String)
  102. }
  103. def citiesJsonFile = new File(appHome + File.separator + "conf" + File.separator + "addressdata" + File.separator + "cities.json")
  104. def citiesJsonArray = jsonSlurper.parse(citiesJsonFile)
  105. citiesJsonArray.each { it ->
  106. CITIES.put(it["code"] as String, it["name"] as String)
  107. }
  108. def countiesJsonFile = new File(appHome + File.separator + "conf" + File.separator + "addressdata" + File.separator + "counties.json")
  109. def countiesJsonArray = jsonSlurper.parse(countiesJsonFile)
  110. countiesJsonArray.each { it ->
  111. COUNTIES.put(it["code"] as String, it["name"] as String)
  112. }
  113. for (Map.Entry<String, String> entry : PROVINCES.entrySet()) {
  114. String result = entry.getValue()
  115. for (String key : provinceKeys) {
  116. result = result.replace(key, "")
  117. }
  118. provinceShort.put(entry.getKey(), result)
  119. }
  120. for (Map.Entry<String, String> entry : CITIES.entrySet()) {
  121. String result = entry.getValue()
  122. if (result.length() > 2) {
  123. for (String key : cityKeys) {
  124. result = result.replace(key, "")
  125. }
  126. cityShort.put(entry.getKey(), result)
  127. }
  128. }
  129. for (Map.Entry<String, String> entry : COUNTIES.entrySet()) {
  130. String result = entry.getValue()
  131. if ("雨花台区" == result) {
  132. result = "雨花区"
  133. } else if ("郑州高新技术产业开发区" == result) {
  134. result = "高新区"
  135. }
  136. if (result.length() > 2) {
  137. for (String key : countyKeys) {
  138. if (result.indexOf(key) > 0) {
  139. result = result.replace(key, "")
  140. }
  141. }
  142. countyShort.put(entry.getKey(), result)
  143. }
  144. }
  145. }
  146. @Override
  147. RetResult<List<ParseAreaResult>> executeList(ProcessStringItem source) {
  148. List<ParseAreaResult> results = parse(source.getItemValue(), false)
  149. return RetResult.<List<ParseAreaResult>> successT().result(results)
  150. }
  151. List<ParseAreaResult> parse(String address, boolean parseAll) {
  152. //整体代码参考 https://github.com/pupuk/addr/blob/master/addr.go和 https://github.com/pupuk/address
  153. //实现,用字符串处理看来是到头了,不要再纠结啥不对了。
  154. //都能运里面使用过高德的正地理编码,不输入完整的门牌号也是有差距的,顶多到区县,
  155. //再不对,可使用百度平台的地址识别,不过从别人测试的结果看也是不能保证的100%
  156. String inputAddress = address
  157. ParseAreaResult extraResult = new ParseAreaResult()
  158. //地址清洗 替换特殊字符,解析手机,座机,邮编,格式化多余空格
  159. address = cleanAddress(address)
  160. //提取手机号
  161. address = parseMobile(address, extraResult)
  162. //提取电话号码
  163. address = parsePhone(address, extraResult)
  164. //提取邮编
  165. address = parseZipCode(address, extraResult)
  166. address = address.replaceAll(" {2,}", BLANK)
  167. // logger.info(address)
  168. String memo = parseMemo(inputAddress)
  169. //解析地址
  170. List<ParseAreaResult> results = parseAddress(address, parseAll)
  171. //将解析的地址结果重新解析一次名称
  172. if ((results != null) && (!results.isEmpty())) {
  173. results.each { r ->
  174. r.setMobile(extraResult.getMobile())
  175. r.setPhone(extraResult.getPhone())
  176. r.setZipCode(extraResult.getZipCode())
  177. parseName(r, 11)
  178. }
  179. } else {
  180. parseName(extraResult, 11)
  181. results.add(extraResult)
  182. }
  183. results.each { it.memo = memo }
  184. return results
  185. }
  186. private String cleanAddress(String address) {
  187. address = address.replaceAll("-", EMPTY)
  188. address = address.replaceAll("\\[.*?]", "")
  189. address = address.replaceAll("【.*?】", "")
  190. for (String key : excludeKeys) {
  191. address = address.replaceAll(key, " ")
  192. }
  193. //有一段替换代码groovy执行不了,改成java执行
  194. return ERPUtils.formatParseAddress(address)
  195. }
  196. /**
  197. * 提取手机号码
  198. */
  199. private static String parseMobile(String address, ParseAreaResult result) {
  200. String mobile = patternGetStr(mobilePattern, address, 0)
  201. if (StringUtils.isNotEmpty(mobile)) {
  202. result.setMobile(mobile)
  203. return address.replaceAll(mobile, BLANK)
  204. }
  205. return address
  206. }
  207. /**
  208. * 提取座机号码
  209. */
  210. private static String parsePhone(String address, ParseAreaResult result) {
  211. String phone = patternGetStr(phonePattern, address, 0)
  212. if (StringUtils.isNotEmpty(phone)) {
  213. result.setPhone(phone)
  214. return address.replaceAll(phone, BLANK)
  215. }
  216. return address
  217. }
  218. /**
  219. * 提取邮编
  220. */
  221. private static String parseZipCode(String address, ParseAreaResult result) {
  222. String zipCode = patternGetStr(zipCodePattern, address, 0)
  223. if (StringUtils.isNotEmpty(zipCode)) {
  224. result.setZipCode(zipCode)
  225. return address.replaceAll(zipCode, BLANK)
  226. }
  227. return address
  228. }
  229. /**
  230. * 提取名称
  231. */
  232. private static void parseName(ParseAreaResult result, int maxLen) {
  233. //设置result
  234. if (StringUtils.isEmpty(result.getName())) {
  235. //List<String> list = Stream.of(result.getDetails().split(" ")).collect(Collectors.toCollection(ArrayList::new));
  236. if (StringUtils.isNotBlank(result.getDetails())) {
  237. List<String> list = result.getDetails().split(" ") as List
  238. AtomicReference<String> name = new AtomicReference<>("")
  239. AtomicInteger index = new AtomicInteger(-1)
  240. list.each { s ->
  241. index.addAndGet(1)
  242. if (StringUtils.isNotEmpty(s) && s.length() < maxLen) {
  243. if (StringUtils.isEmpty(name.get()) || name.get().length() > s.length()) {
  244. name.set(s)
  245. }
  246. }
  247. }
  248. if (StringUtils.isNotEmpty(name.get())) {
  249. result.setName(name.get().trim())
  250. list.remove(index.get())
  251. result.setDetails(list.stream().collect(Collectors.joining(" ")))
  252. }
  253. } else {
  254. result.setName("")
  255. }
  256. }
  257. }
  258. private static String parseMemo(String address) {
  259. def result = []
  260. def matcher = address =~ /([\[【])(.*?)([]】])/
  261. matcher.each { result << it[2] }
  262. return result.join(",")
  263. }
  264. private static String patternGetStr(Pattern pattern, CharSequence content, int groupIndex) {
  265. if (null != content && null != pattern) {
  266. Matcher matcher = pattern.matcher(content)
  267. return matcher.find() ? matcher.group(groupIndex) : null
  268. } else {
  269. return null
  270. }
  271. }
  272. private List<ParseAreaResult> parseAddress(String address, boolean parseAll) {
  273. List<ParseAreaResult> list = new ArrayList<>()
  274. list.addAll(0, parseByProvince(address))
  275. if (parseAll || list.isEmpty() || !list.get(0).getParse()) {
  276. list.addAll(0, parseByCity(address))
  277. if (parseAll || list.isEmpty() || !list.get(0).getParse()) {
  278. list.addAll(0, parseByCounty(address))
  279. }
  280. }
  281. // 可信度排序
  282. list.sort { a, b ->
  283. int aNameLength = StringUtils.isEmpty(a.name) ? -1 : a.getName().length()
  284. int bNameLength = StringUtils.isEmpty(b.getName()) ? -1 : b.getName().length()
  285. return a.getParse() && !b.getParse() ? -1 : !a.getParse() && b.getParse() ? 1 : aNameLength > bNameLength ? 1 : aNameLength < bNameLength ? -1 : 0
  286. }
  287. return list
  288. }
  289. /**
  290. * 通过区解析地址
  291. * @param addressBase
  292. * @return
  293. */
  294. private List<ParseAreaResult> parseByCounty(String addressBase) {
  295. List<ParseAreaResult> results = new ArrayList<>()
  296. ParseAreaResult result = new ParseAreaResult()
  297. result.setType("parseByCounty")
  298. String address = addressBase
  299. for (Map.Entry<String, String> entry : COUNTIES.entrySet()) {
  300. String countyCode = entry.getKey()
  301. String countyName = entry.getValue()
  302. int index = address.indexOf(countyName)
  303. String shortCounty = index > -1 ? "" : countyShort.get(countyCode)
  304. int countyLength = StringUtils.isNotEmpty(shortCounty) ? shortCounty.length() : countyName.length()
  305. if (StringUtils.isNotEmpty(shortCounty)) {
  306. index = address.indexOf(shortCounty)
  307. }
  308. if (index > -1) {
  309. if (countyCode.contains("-")) {
  310. countyCode = countyCode.split("-")[0]
  311. }
  312. result.setCode(countyCode)
  313. result.setCounty(countyName)
  314. result.setCountyCode(countyCode)
  315. String cityCode = countyCode.substring(0, 4) + "00"
  316. String city = CITIES.get(cityCode)
  317. result.setCityCode(cityCode)
  318. result.setCity(city)
  319. String provinceCode = countyCode.substring(0, 2) + "0000"
  320. String province = PROVINCES.get(provinceCode)
  321. result.setProvinceCode(provinceCode)
  322. result.setProvince(province)
  323. String leftAddress = address.substring(0, index)
  324. String _provinceName = "", _cityName = ""
  325. if (StringUtils.isNotEmpty(leftAddress)) {
  326. _provinceName = province
  327. int _index = leftAddress.indexOf(_provinceName)
  328. if (_index == -1) {
  329. _provinceName = provinceShort.get(countyCode.substring(0, 2) + "0000")
  330. _index = leftAddress.indexOf(_provinceName)
  331. if (_index == -1) {
  332. _provinceName = ""
  333. }
  334. }
  335. if (StringUtils.isNotEmpty(_provinceName)) {
  336. leftAddress = leftAddress.replaceAll(_provinceName, "")
  337. }
  338. _cityName = city
  339. _index = leftAddress.indexOf(_cityName)
  340. if (_index == -1) {
  341. _cityName = cityShort.get(countyCode.substring(0, 4) + "00")
  342. _index = (StringUtils.isBlank(_cityName)) ? -1 : leftAddress.indexOf(_cityName)
  343. if (_index == -1) {
  344. _cityName = ""
  345. }
  346. }
  347. if (StringUtils.isNotEmpty(_cityName)) {
  348. leftAddress = leftAddress.replaceAll(_cityName, "")
  349. }
  350. if (StringUtils.isNotEmpty(leftAddress)) {
  351. result.setName(leftAddress.trim())
  352. }
  353. }
  354. address = address.substring(index + countyLength)
  355. if (StringUtils.isNotEmpty(_provinceName) || StringUtils.isNotEmpty(_cityName)) {
  356. result.setParse(true)
  357. break
  358. } else {
  359. //如果没有识别到地区 缓存本次结果,并重置数据
  360. ParseAreaResult newResult = new ParseAreaResult()
  361. newResult.mobile = result.mobile
  362. newResult.phone = result.phone
  363. newResult.zipCode = result.zipCode
  364. newResult.province = result.province
  365. newResult.provinceCode = result.provinceCode
  366. newResult.city = result.city
  367. newResult.cityCode = result.cityCode
  368. newResult.county = result.county
  369. newResult.countyCode = result.countyCode
  370. newResult.address = result.address
  371. newResult.details = result.details
  372. newResult.code = result.code
  373. newResult.name = result.name
  374. newResult.type = result.type
  375. newResult.parse = result.parse
  376. newResult.setDetails(address.trim())
  377. results.add(0, newResult)
  378. result.clean()
  379. address = addressBase
  380. }
  381. }
  382. }
  383. if (StringUtils.isNotEmpty(result.getCode())) {
  384. result.setDetails(address.trim())
  385. results.add(0, result)
  386. }
  387. return results
  388. }
  389. /**
  390. * 通过省解析地址
  391. * @param addressBase
  392. * @return
  393. */
  394. private List<ParseAreaResult> parseByCity(String addressBase) {
  395. List<ParseAreaResult> results = new ArrayList<>()
  396. ParseAreaResult result = new ParseAreaResult()
  397. result.setType("parseByCity")
  398. String address = addressBase
  399. for (Map.Entry<String, String> entry : CITIES.entrySet()) {
  400. String cityCode = entry.getKey()
  401. String cityName = entry.getValue()
  402. int index = address.indexOf(cityName)
  403. String shortCity = index > -1 ? "" : cityShort.get(cityCode)
  404. int cityLength = StringUtils.isNotEmpty(shortCity) ? shortCity.length() : cityName.length()
  405. if (StringUtils.isNotEmpty(shortCity)) {
  406. index = address.indexOf(shortCity)
  407. }
  408. if (index > -1) {
  409. result.setCode(cityCode)
  410. result.setCity(cityName)
  411. result.setCityCode(cityCode)
  412. String provinceCode = cityCode.substring(0, 2) + "0000"
  413. String province = PROVINCES.get(provinceCode)
  414. result.setProvinceCode(provinceCode)
  415. result.setProvince(province)
  416. String leftAddress = address.substring(0, index)
  417. String _provinceName = ""
  418. if (StringUtils.isNotEmpty(leftAddress)) {
  419. _provinceName = province
  420. int _index = leftAddress.indexOf(_provinceName)
  421. if (_index == -1) {
  422. _provinceName = provinceShort.get(cityCode.substring(0, 2) + "0000")
  423. _index = leftAddress.indexOf(_provinceName)
  424. if (_index == -1) {
  425. _provinceName = ""
  426. }
  427. }
  428. if (StringUtils.isNotEmpty(_provinceName)) {
  429. leftAddress = leftAddress.replace(_provinceName, "")
  430. }
  431. if (StringUtils.isNotEmpty(leftAddress)) {
  432. result.setName(leftAddress)
  433. }
  434. }
  435. address = address.substring(index + cityLength)
  436. address = parseAreaByCity(address, result)
  437. if (StringUtils.isNotEmpty(_provinceName) || StringUtils.isNotEmpty(result.getCounty())) {
  438. result.setParse(true)
  439. break
  440. } else {
  441. //如果没有识别到地区 缓存本次结果,并重置数据
  442. ParseAreaResult newResult = new ParseAreaResult()
  443. newResult.mobile = result.mobile
  444. newResult.phone = result.phone
  445. newResult.zipCode = result.zipCode
  446. newResult.province = result.province
  447. newResult.provinceCode = result.provinceCode
  448. newResult.city = result.city
  449. newResult.cityCode = result.cityCode
  450. newResult.county = result.county
  451. newResult.countyCode = result.countyCode
  452. newResult.address = result.address
  453. newResult.details = result.details
  454. newResult.code = result.code
  455. newResult.name = result.name
  456. newResult.type = result.type
  457. newResult.parse = result.parse
  458. newResult.setDetails(address.trim())
  459. results.add(0, newResult)
  460. result.clean()
  461. address = addressBase
  462. }
  463. }
  464. }
  465. if (StringUtils.isNotEmpty(result.getCode())) {
  466. result.setDetails(address.trim())
  467. results.add(0, result)
  468. }
  469. return results
  470. }
  471. /**
  472. * 通过省解析地址
  473. * @param addressBase
  474. * @return
  475. */
  476. private List<ParseAreaResult> parseByProvince(String addressBase) {
  477. List<ParseAreaResult> results = new ArrayList<>()
  478. ParseAreaResult result = new ParseAreaResult()
  479. result.setType("parseByProvince")
  480. String address = addressBase
  481. for (Map.Entry<String, String> entry : PROVINCES.entrySet()) {
  482. String code = entry.getKey()
  483. String province = entry.getValue()
  484. int index = address.indexOf(province)
  485. String shortProvince = index > -1 ? "" : provinceShort.get(code)
  486. int provinceLength = StringUtils.isNotEmpty(shortProvince) ? shortProvince.length() : province.length()
  487. if (StringUtils.isNotEmpty(shortProvince)) {
  488. index = address.indexOf(shortProvince)
  489. }
  490. if (index > -1) {
  491. if (index > 0) {
  492. result.setName(address.substring(0, index).trim())
  493. address = address.substring(index).trim()
  494. }
  495. result.setCode(code)
  496. result.setProvince(province)
  497. result.setProvinceCode(code)
  498. String _address = address.substring(provinceLength)
  499. if (StringUtils.isNotBlank(_address)) {
  500. if (!_address.startsWith("市") || _address.indexOf(province) > -1) {
  501. address = _address
  502. }
  503. }
  504. //如果是用短名匹配的 要替换省关键字
  505. if (StringUtils.isNotEmpty(shortProvince)) {
  506. for (String key : provinceKeys) {
  507. if (address.indexOf(key) == 0) {
  508. address = address.substring(key.length())
  509. }
  510. }
  511. }
  512. String __address = parseCityByProvince(address, result)
  513. if (StringUtils.isEmpty(result.getCity())) {
  514. __address = parseCountyByProvince(address, result)
  515. }
  516. if (StringUtils.isNotEmpty(result.getCity())) {
  517. address = __address
  518. result.setParse(true)
  519. break
  520. } else {
  521. //如果没有识别到地区 缓存本次结果,并重置数据
  522. ParseAreaResult newResult = new ParseAreaResult()
  523. newResult.mobile = result.mobile
  524. newResult.phone = result.phone
  525. newResult.zipCode = result.zipCode
  526. newResult.province = result.province
  527. newResult.provinceCode = result.provinceCode
  528. newResult.city = result.city
  529. newResult.cityCode = result.cityCode
  530. newResult.county = result.county
  531. newResult.countyCode = result.countyCode
  532. newResult.address = result.address
  533. newResult.details = result.details
  534. newResult.code = result.code
  535. newResult.name = result.name
  536. newResult.type = result.type
  537. newResult.parse = result.parse
  538. newResult.setDetails(address.trim())
  539. results.add(0, newResult)
  540. result.clean()
  541. address = addressBase
  542. }
  543. }
  544. }
  545. //设置code
  546. if (StringUtils.isNotEmpty(result.getCode())) {
  547. result.setDetails(address.trim())
  548. results.add(0, result)
  549. }
  550. return results
  551. }
  552. private String parseCountyByProvince(String address, ParseAreaResult result) {
  553. Map<String, String> counties = getTargetsByCode(AreaEnum.COUNTY, result.getCode())
  554. for (Map.Entry<String, String> entry : counties.entrySet()) {
  555. String countyCode = entry.getKey()
  556. String countyName = entry.getValue()
  557. int index = address.indexOf(countyName)
  558. String shortCounty = index > -1 ? "" : countyShort.get(countyCode)
  559. int countyLength = StringUtils.isNotEmpty(shortCounty) ? shortCounty.length() : countyName.length()
  560. if (StringUtils.isNotEmpty(shortCounty)) {
  561. index = address.indexOf(shortCounty)
  562. }
  563. if (index > -1 && index < 6) {
  564. if (countyCode.contains("-")) {
  565. countyCode = countyCode.split("-")[0]
  566. }
  567. result.setCode(countyCode)
  568. result.setCounty(countyName)
  569. result.setCountyCode(countyCode)
  570. String cityCode = countyCode.substring(0, 4) + "00"
  571. String cityName = CITIES.get(cityCode)
  572. result.setCity(cityName)
  573. result.setCityCode(cityCode)
  574. address = address.substring(index + countyLength)
  575. if (StringUtils.isNotEmpty(shortCounty)) {
  576. for (String key : countyKeys) {
  577. if (address.indexOf(key) == 0) {
  578. address = address.substring(key.length())
  579. }
  580. }
  581. }
  582. break
  583. }
  584. }
  585. return address
  586. }
  587. /**
  588. * 通过省解析城市信息
  589. * @param address
  590. * @param result
  591. * @return
  592. */
  593. private String parseCityByProvince(String address, ParseAreaResult result) {
  594. Map<String, String> cities = getTargetsByCode(AreaEnum.CITY, result.getCode())
  595. for (Map.Entry<String, String> entry : cities.entrySet()) {
  596. String cityCode = entry.getKey()
  597. String cityName = entry.getValue()
  598. int index = address.indexOf(cityName)
  599. String shortCity = index > -1 ? "" : cityShort.get(cityCode)
  600. int cityLength = StringUtils.isNotEmpty(shortCity) ? shortCity.length() : cityName.length()
  601. if (StringUtils.isNotEmpty(shortCity)) {
  602. index = address.indexOf(shortCity)
  603. }
  604. if (index > -1 && index < 3) {
  605. result.setCode(cityCode)
  606. result.setCity(cityName)
  607. result.setCityCode(cityCode)
  608. address = address.substring(index + cityLength)
  609. //如果是用短名匹配的 要替换市关键字
  610. if (StringUtils.isNotEmpty(shortCity)) {
  611. String finalAddress = address
  612. for (String key : cityKeys) {
  613. if (address.indexOf(key) == 0 && !StringUtils.equals(key, "市")) {
  614. //排除几个会导致异常的解析
  615. boolean anyMatch = Stream.of("市北区", "市南区", "市中区", "市辖区").anyMatch { v -> finalAddress.indexOf(v) == 0 }
  616. if (!anyMatch) {
  617. address = address.substring(key.length())
  618. }
  619. }
  620. }
  621. }
  622. address = parseAreaByCity(address, result)
  623. break
  624. }
  625. }
  626. return address
  627. }
  628. /**
  629. * 通过城市解析地区信息
  630. * @param address
  631. * @param result
  632. * @return
  633. */
  634. private String parseAreaByCity(String address, ParseAreaResult result) {
  635. Map<String, String> counties = getTargetsByCode(AreaEnum.COUNTY, result.getCode())
  636. for (Map.Entry<String, String> entry : counties.entrySet()) {
  637. String countyCode = entry.getKey()
  638. String countyName = entry.getValue()
  639. int index = address.indexOf(countyName)
  640. String shortCounty = index > -1 ? "" : countyShort.get(countyCode)
  641. int countyLength = StringUtils.isNotEmpty(shortCounty) ? shortCounty.length() : countyName.length()
  642. if (StringUtils.isNotEmpty(shortCounty)) {
  643. index = address.indexOf(shortCounty)
  644. }
  645. if (index > -1 && index < 3) {
  646. if (countyCode.contains("-")) {
  647. countyCode = countyCode.split("-")[0]
  648. }
  649. result.setCode(countyCode)
  650. result.setCounty(countyName)
  651. result.setCountyCode(countyCode)
  652. address = address.substring(index + countyLength)
  653. if (StringUtils.isNotEmpty(shortCounty)) {
  654. for (String key : countyKeys) {
  655. if (address.indexOf(key) == 0) {
  656. address = address.substring(key.length())
  657. }
  658. }
  659. }
  660. break
  661. }
  662. }
  663. return address
  664. }
  665. /**
  666. * 通过编码获取省市集合对象
  667. *
  668. * @param target 省,市枚举
  669. * @param code 编码,为地区,市,省
  670. * @return 地址对象
  671. */
  672. private Map<String, String> getTargetsByCode(AreaEnum target, String code) {
  673. Map<String, String> targets = null
  674. if (AreaEnum.PROVINCE == target) {
  675. String provinceCode = code.substring(0, 2)
  676. targets = putTargets(provinceCode, PROVINCES)
  677. } else if (AreaEnum.CITY == target) {
  678. String provinceCode = code.substring(0, 2)
  679. targets = putTargets(provinceCode, CITIES)
  680. } else if (AreaEnum.COUNTY == target) {
  681. if ("00" == code.substring(2, 4)) {
  682. String provinceCode = code.substring(0, 2)
  683. targets = putTargets(provinceCode, COUNTIES)
  684. } else {
  685. String cityCode = code.substring(0, 4)
  686. targets = putTargets(cityCode, COUNTIES)
  687. }
  688. }
  689. return targets
  690. }
  691. /**
  692. * 查找sources中key以preCode开头的对象,并存储到targets中
  693. * 其中break必须要依赖于数据是有一定顺序的,必须targets记录在同一范围,中间不能插入其他对象
  694. *
  695. * @param preCode
  696. * @param sources
  697. */
  698. private static Map<String, String> putTargets(String preCode, Map<String, String> sources) {
  699. Map<String, String> targets = new LinkedHashMap<>()
  700. for (Map.Entry<String, String> entry : sources.entrySet()) {
  701. int index = entry.getKey().indexOf(preCode)
  702. if (index == 0) {
  703. targets.put(entry.getKey(), entry.getValue())
  704. } else if (targets.size() > 0 && index != 0) {
  705. break
  706. }
  707. }
  708. return targets
  709. }
  710. }