AddressQueryEngine.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. package com.skyversation.poiaddr.addquery;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.skyversation.poiaddr.bean.AddressResult;
  6. import com.skyversation.poiaddr.bean.GeoJsonBean;
  7. import com.skyversation.poiaddr.bean.WDToken;
  8. import com.skyversation.poiaddr.entity.AmapAddressV3;
  9. import com.skyversation.poiaddr.service.AreaService;
  10. import com.skyversation.poiaddr.util.net.AddressNetTools;
  11. import com.skyversation.poiaddr.util.status.AddressLevel;
  12. import com.skyversation.poiaddr.util.status.AddressResultEnum;
  13. import org.springframework.http.HttpMethod;
  14. import org.springframework.http.ResponseEntity;
  15. import org.springframework.stereotype.Service;
  16. import org.springframework.util.StringUtils;
  17. import org.apache.commons.codec.binary.Base64;
  18. import javax.crypto.Mac;
  19. import javax.crypto.spec.SecretKeySpec;
  20. import java.util.*;
  21. public class AddressQueryEngine {
  22. private static AddressQueryEngine instance = new AddressQueryEngine();
  23. private AddressQueryEngine() {
  24. }
  25. public synchronized static AddressQueryEngine getInstance() {
  26. if (instance == null) {
  27. instance = new AddressQueryEngine();
  28. }
  29. return instance;
  30. }
  31. private WDToken wdToken = null;
  32. /***
  33. * 单条地名搜索通用方法,搜索顺序 1. 武大吉奥; 2. 市四中心; 3. 高德搜索; 4. 高德高级搜索;
  34. * @param addrs
  35. * @return
  36. */
  37. public AddressResult commonSearchByName(List<String> addrs) {
  38. if (addrs == null || addrs.size() < 1) {
  39. return null;
  40. }
  41. AddressResult addressResult = new AddressResult();
  42. // 数据库查询
  43. for (String addr : addrs) {
  44. if (addr.startsWith("中山") && !addr.startsWith("中山街道")) {
  45. addr = addr.replace("中山", "中山街道");
  46. }
  47. // 优先进行数据库查询
  48. List<AmapAddressV3> dbPois = AreaService.getInstance().getAddressPoisByAddr(addr);
  49. JSONArray pois = new JSONArray();
  50. if (dbPois != null && dbPois.size() > 0) {
  51. System.out.println("数据库查询有结果!!!!");
  52. pois.addAll(dbPois);
  53. return new TransfromDataTool().gdV3ResultToResult(addr, pois, false);
  54. }
  55. }
  56. /*for (String addr : addrs) {
  57. // 创建请求
  58. addressResult = sj_szxSearchByName(addr, 3);
  59. if (addressResult != null) {
  60. addressResult.setCode(AddressResultEnum.SZX_SUCCESS);
  61. addressResult.setMessage("成功");
  62. return getCjWgWgwByLoc(addressResult);
  63. }
  64. }*/
  65. // 市中心转发的测绘院地名地址服务
  66. for (String addr : addrs) {
  67. // 创建请求
  68. addressResult = szxSearchByName(addr);
  69. if (addressResult != null) {
  70. addressResult.setCode(AddressResultEnum.SZX_SUCCESS);
  71. addressResult.setMessage("成功");
  72. return getCjWgWgwByLoc(addressResult);
  73. }
  74. }
  75. // TODO 如果多次尝试请求市中心地址后,还是请求失败就使用高德地名地址搜索
  76. for (String addr : addrs) {
  77. // 创建请求(要返回对应的搜索地址,返回地址,总分,市:cityname,街道:adname,村居:community)
  78. addressResult = gdV3SearchByName(addr);
  79. if (addressResult != null) {
  80. addressResult.setCode(AddressResultEnum.SZX_SUCCESS);
  81. addressResult.setMessage("成功");
  82. return getCjWgWgwByLoc(addressResult);
  83. }
  84. }
  85. addressResult.setCode(AddressResultEnum.RESULT_NULL);
  86. addressResult.setMessage("失败");
  87. return addressResult;
  88. }
  89. /***
  90. * 市四中心地名搜索
  91. * @param address
  92. * @return
  93. */
  94. public AddressResult szxSearchByName(String address) {
  95. if (!address.startsWith("上海")) {
  96. address = "上海市" + address;
  97. }
  98. if (address.startsWith("中山") && !address.startsWith("中山街道")) {
  99. address = address.replace("中山", "中山街道");
  100. }
  101. ResponseEntity response = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.GET, Constant.SZX_HLW_URL + address, null, null, 3);
  102. if (response == null) {
  103. return null;
  104. }
  105. String body = response.getBody() + "";
  106. if (!StringUtils.hasText(body))
  107. return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果");
  108. try {
  109. JSONObject json = JSONObject.parseObject(body);
  110. return TransfromDataTool.szxResultToResult(json, address);
  111. } catch (Exception e) {
  112. return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败");
  113. }
  114. }
  115. /***
  116. * 武大吉奥单条地名搜索
  117. * @param address
  118. */
  119. public AddressResult wdjaSearchByName(String address) {
  120. System.out.println("<<<<<<<<<<----------开始武大吉奥地名地址搜索------------>>>>>>>>>>>>>");
  121. if (wdToken == null || System.currentTimeMillis() - wdToken.getTime() > 36000000) {
  122. wdToken = AddressTools.getInstance().getWDToken(Constant.WD_USER_NAME, Constant.WD_USER_PWD);
  123. if (wdToken == null) {
  124. return null;
  125. }
  126. wdToken.setTime(System.currentTimeMillis());
  127. }
  128. if (wdToken == null)
  129. return AddressTools.getInstance().faildQuery(AddressResultEnum.NO_TOKEN, "token获取失败");
  130. String token = wdToken.getToken();
  131. String url = Constant.GET_ADDRESS_MEG_URL + "?token=" + token + "&addr=" + address;
  132. String body = null;
  133. try {
  134. body = AddressNetTools.getInstance().wdSendGetRequest(url);
  135. } catch (Exception e) {
  136. e.toString();
  137. }
  138. if (body == null || body.equals("null") || !StringUtils.hasText(body))
  139. return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果");
  140. try {
  141. JSONObject json = JSONObject.parseObject(body);
  142. return TransfromDataTool.wdResultToResult(json);
  143. } catch (Exception e) {
  144. return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败");
  145. }
  146. }
  147. public static Map<String, String> initSigns() {
  148. Map<String, String> headerMap = new HashMap<>();
  149. String timestamp = System.currentTimeMillis() + "";
  150. String appCode = "7unv4vbwqxnq4a7m9h";
  151. String UUid = UUID.randomUUID().toString();
  152. String appSecret = "w6tawvf4k3ck4ikij9";
  153. headerMap.put("x-timestamp", timestamp);
  154. headerMap.put("x-appcode", appCode);
  155. headerMap.put("x-uuid", UUid);
  156. // 签名
  157. headerMap.put("x-sign", AddressQueryEngine.getSigns(timestamp, appCode, UUid, appSecret));
  158. return headerMap;
  159. }
  160. public static String getSigns(String timestamp, String appCode, String UUid, String appSecret) {
  161. // 先拼接
  162. String signData = timestamp + appCode + UUid;
  163. // 生成sign
  164. String sign = "";
  165. try {
  166. Mac sha256 = Mac.getInstance("HmacSHA256");
  167. sha256.init(new SecretKeySpec(appSecret.getBytes(), "HmacSHA256"));
  168. byte[] result = sha256.doFinal(signData.getBytes());
  169. sign = Base64.encodeBase64String(result);
  170. } catch (Exception e) {
  171. System.err.println("sign 生成异常:" + e);
  172. }
  173. return sign;
  174. }
  175. /**
  176. * 关键字地名地址搜索,专用搜索处理逻辑
  177. *
  178. * @param address
  179. * @param level
  180. * @return
  181. */
  182. public AddressResult sj_szxSearchByName(String address, Integer level) {
  183. // 鉴权
  184. JSONObject params = new JSONObject();
  185. JSONArray requestJson = new JSONArray();
  186. JSONObject paramObject = new JSONObject();
  187. paramObject.put("name", "query");
  188. paramObject.put("position", "QUERY");
  189. switch (level) {
  190. case 3:
  191. paramObject.put("value", address);
  192. break;
  193. case 2:
  194. if (address.contains("号")) {
  195. paramObject.put("value", address.substring(0, address.lastIndexOf("号") + 1));
  196. } else {
  197. level--;
  198. return sj_szxSearchByName(address, level);
  199. }
  200. break;
  201. case 1:
  202. if (address.contains("弄")) {
  203. paramObject.put("value", address.substring(0, address.lastIndexOf("弄") + 1));
  204. } else {
  205. paramObject.put("value", address);
  206. }
  207. break;
  208. }
  209. if (!address.startsWith("上海")) {
  210. paramObject.put("value", "上海市" + paramObject.get("value"));
  211. }
  212. requestJson.add(paramObject);
  213. // 判断是否是关键字版搜索服务
  214. if (Constant.SJ_SZX_SEARCH_BY_NAME.contains("1742459783686")) {
  215. JSONObject paramObject2 = new JSONObject();
  216. paramObject2.put("name", "region");
  217. paramObject2.put("position", "QUERY");
  218. paramObject2.put("value", Constant.getAMAP_CITY_CODE());
  219. requestJson.add(paramObject2);
  220. JSONObject paramObject3 = new JSONObject();
  221. paramObject3.put("name", "page_size");
  222. paramObject3.put("position", "QUERY");
  223. paramObject3.put("value", "10");
  224. requestJson.add(paramObject3);
  225. }
  226. params.put("requestJson", requestJson);
  227. // 发起请求
  228. ResponseEntity response = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.POST, Constant.SJ_SZX_SEARCH_BY_NAME, params, initSigns(), 5);
  229. if (response != null && response.hasBody()) {
  230. String body = response.getBody() + "";
  231. if (!StringUtils.hasText(body)) {
  232. if (level > 0) {
  233. level--;
  234. return sj_szxSearchByName(address, level);
  235. }
  236. return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果");
  237. }
  238. try {
  239. if (body.indexOf("[") != 0) {
  240. AddressResult addressResult = TransfromDataTool.szxResultToResult(JSONObject.parseObject(body), address);
  241. if (addressResult.getCode().equals(AddressResultEnum.RESULT_NULL) && level > 0) {
  242. level--;
  243. return sj_szxSearchByName(address, level);
  244. }
  245. return addressResult;
  246. } else {
  247. // 将得分最高的结果映射到实体类
  248. return TransfromDataTool.szxResultToResult2(com.skyversation.poiaddr.util.AddressTools.getInstance().findBestMatch(address, JSONArray.parseArray(body), "address"));
  249. }
  250. } catch (Exception e) {
  251. System.err.println("请求地址:" + address + ";返回结果:" + body + ";处理异常:" + e);
  252. return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败");
  253. }
  254. } else {
  255. if (level > 0) {
  256. level--;
  257. return sj_szxSearchByName(address, level);
  258. }
  259. System.out.println("地址[" + address + "]未查询到数据!");
  260. return null;
  261. }
  262. }
  263. /***
  264. * 高德普通地名搜索
  265. * @param address
  266. * @return
  267. */
  268. public AddressResult gdSearchByName(String address) {
  269. String geoUrl = Constant.AMAP_GEO_URL + "?key=" + Constant.AMAP_KEY + "&address=" + address + "&city=" + Constant.getAMAP_CITY_CODE() + "&output=JSON";
  270. ResponseEntity response = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.GET, geoUrl, null, null, 0);
  271. if (response != null && response.getBody() != null) {
  272. String body = response.getBody() + "";
  273. if (!StringUtils.hasText(body))
  274. return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果");
  275. try {
  276. JSONObject json = JSONObject.parseObject(body);
  277. return TransfromDataTool.gdResultToResult(json);
  278. } catch (Exception e) {
  279. System.err.println(e);
  280. return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败");
  281. }
  282. } else {
  283. return null;
  284. }
  285. }
  286. /***
  287. * 高德高级地名搜索
  288. * @param address
  289. * @return
  290. */
  291. public AddressResult gdV3SearchByName(String address) {
  292. if (address.startsWith("中山") && !address.startsWith("中山街道")) {
  293. address = address.replace("中山", "中山街道");
  294. }
  295. JSONArray pois = new JSONArray();
  296. String geoUrl =
  297. Constant.AMAP_SEARCH_NAME_V3 + "?key=" + Constant.AMAP_KEY + "&types=" + Constant.AMAP_SEARCH_TYPES +
  298. "&keywords=" + address + "&city=" + Constant.getAMAP_CITY_CODE() + "&offset=20";
  299. ResponseEntity responseEntity = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.GET, geoUrl, null, null, 0);
  300. if (responseEntity.hasBody()) {
  301. String body = responseEntity.getBody() + "";
  302. if (!StringUtils.hasText(body)) {
  303. return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_NULL, "搜索无结果");
  304. }
  305. JSONObject json = JSONObject.parseObject(body);
  306. if (json.containsKey("pois")) {
  307. pois.addAll(json.getJSONArray("pois"));
  308. }
  309. // if (json.containsKey("count")) {
  310. // int count = Integer.parseInt(json.get("count") + "");
  311. // if (count > 20) {
  312. // for (int i = 2; i < (count % 20 + 1); i++) {
  313. // geoUrl =
  314. // Constant.AMAP_SEARCH_NAME_V3 + "?key=" + Constant.AMAP_KEY + "&types=" + Constant.AMAP_SEARCH_TYPES +
  315. // "&keywords=" + address + "&city=" + Constant.getAMAP_CITY_CODE() + "&offset=20&page=" + i;
  316. // ResponseEntity responseEntity2 = AddressNetTools.getInstance().requestGetOrPost(HttpMethod.GET, geoUrl, null, null, 0);
  317. // if (responseEntity2.hasBody()) {
  318. // body = responseEntity2.getBody() + "";
  319. // }
  320. // if (!StringUtils.hasText(body)) {
  321. // return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_AGAIN_NULL, "多次搜索无结果");
  322. // }
  323. // JSONObject json2 = JSONObject.parseObject(body);
  324. // if (json2.containsKey(pois)) {
  325. // pois.addAll(JSONObject.parseObject(body).getJSONArray("pois"));
  326. // }
  327. // }
  328. // }
  329. // }
  330. try {
  331. return new TransfromDataTool().gdV3ResultToResult(address, pois, true);
  332. } catch (Exception e) {
  333. System.err.println(e);
  334. e.printStackTrace();
  335. return AddressTools.getInstance().faildQuery(AddressResultEnum.DATA_FROMAT_FAILD, "格式化失败");
  336. }
  337. } else {
  338. return AddressTools.getInstance().faildQuery(AddressResultEnum.RESULT_AGAIN_NULL, "高德V3分页查询无结果");
  339. }
  340. }
  341. /***
  342. * 根据搜索地址,赋值村居、网格、微格网信息
  343. * @param result
  344. * @return
  345. */
  346. public AddressResult getCjWgWgwByLoc(AddressResult result) {
  347. if (result == null || result.getData() == null || result.getData().size() < 1) {
  348. return result;
  349. } else {
  350. AreaService areaService = AreaService.getInstance();
  351. for (AddressResult.ContentBean content : result.getData()) {
  352. if ((content.getAdname() == null || content.getAdname().isEmpty() || content.getCityname() == null || content.getCityname().isEmpty() || content.getCommunity() == null || content.getCommunity().isEmpty()) && content.getLat() != null && content.getLon() != null) {
  353. // 判断是否存在行政区划数据
  354. if (content.getCityname() == null || content.getCityname().isEmpty()) {
  355. GeoJsonBean adBean = areaService.isInadPolygon(content.getLon(), content.getLat());
  356. content.setAdJson(adBean == null ? new JSONObject() : adBean.getProperties());
  357. }
  358. // 判断是否存在街镇数据
  359. if (content.getAdname() == null || content.getAdname().isEmpty()) {
  360. GeoJsonBean townBean = areaService.isInTownPolygon(content.getLon(), content.getLat());
  361. content.setTownJson(townBean == null ? new JSONObject() : townBean.getProperties());
  362. }
  363. // 判断是否存在村居数据
  364. if (content.getCommunity() == null || content.getCommunity().isEmpty()) {
  365. GeoJsonBean cjBean = areaService.isInResidentialCommitteePolygon(content.getLon(), content.getLat());
  366. content.setCjJson(cjBean == null ? new JSONObject() : cjBean.getProperties());
  367. }
  368. }
  369. }
  370. return result;
  371. }
  372. }
  373. //
  374. public static boolean isNotEmptyOrBlank(String str) {
  375. return str != null && !str.trim().isEmpty();
  376. }
  377. /**
  378. * 1. 搜索到结果就返回第一个;
  379. * 2. 搜索到结果去除行政区划后,存在包含关系,则使用;
  380. * 3. 搜索到结果,数字进行分词,数字匹配则使用;
  381. * 4. 搜索到结果,数字与文本均匹配,则使用;
  382. * 5. 结果与基准数据完全一致,则使用。
  383. *
  384. * @param result
  385. * @param level
  386. * @return
  387. */
  388. public AddressResult.ContentBean verificaData(AddressResult result, AddressLevel level, String addr) {
  389. switch (level) {
  390. case LEVEL_1: {
  391. if (result != null && result.getData() != null && result.getData().size() > 0) {
  392. return result.getData().get(0);
  393. } else {
  394. return null;
  395. }
  396. }
  397. // 2. 搜索到结果去除行政区划后,存在包含关系,则使用;
  398. case LEVEL_CONTAINS_2: {
  399. if (result != null && result.getData() != null && result.getData().size() > 0) {
  400. List<AddressResult.ContentBean> contentBean = result.getData();
  401. for (AddressResult.ContentBean contentBean1 : contentBean) {
  402. if (contentBean1.getAddress() != null) {
  403. String address = townReplaceAll(addressReplaceAll(contentBean1.getAddress()));
  404. String address2 = townReplaceAll(addressReplaceAll(addr));
  405. if (isNotEmptyOrBlank(address) && address.contains(address2)) {
  406. return contentBean1;
  407. }
  408. }
  409. }
  410. } else {
  411. return null;
  412. }
  413. }
  414. // 3. 搜索到结果,数字进行分词,数字匹配则使用;
  415. case LEVLE_NUMBER_3: {
  416. if (result != null && result.getData() != null && result.getData().size() > 0) {
  417. List<AddressResult.ContentBean> contentBean = result.getData();
  418. for (AddressResult.ContentBean contentBean1 : contentBean) {
  419. if (contentBean1.getAddress() != null) {
  420. Set<String> address = tokenizeString(contentBean1.getAddress()).get(1);
  421. if (address != null && address.size() > 1) {
  422. Set<String> address2 = tokenizeString(addr).get(1);
  423. int addressSize = address.size();
  424. for (String addr2 : address2) {
  425. if (address.contains(addr2)) {
  426. addressSize--;
  427. if (addressSize == 0) {
  428. return contentBean1;
  429. }
  430. }
  431. }
  432. }
  433. }
  434. }
  435. } else {
  436. return null;
  437. }
  438. }
  439. // 4. 搜索到结果,数字与文本均匹配,则使用;
  440. case LEVEL_NUMBER_TEXT_4: {
  441. if (result != null && result.getData() != null && result.getData().size() > 0) {
  442. List<AddressResult.ContentBean> contentBean = result.getData();
  443. for (AddressResult.ContentBean contentBean1 : contentBean) {
  444. if (contentBean1.getAddress() != null) {
  445. Set<String> addressString = tokenizeString(contentBean1.getAddress()).get(0);
  446. Set<String> addressNumber = tokenizeString(contentBean1.getAddress()).get(1);
  447. Set<String> address2String = tokenizeString(addr).get(0);
  448. Set<String> address2Number = tokenizeString(addr).get(1);
  449. if (addressString != null && addressString.size() > 1) {
  450. int addressStrSize = addressString.size();
  451. for (String addr2str : address2String) {
  452. if (addressString.contains(addr2str)) {
  453. addressStrSize--;
  454. if (addressStrSize == 0) {
  455. int addressNumSize = addressNumber.size();
  456. for (String addr2Num : address2Number) {
  457. if (addressNumber.contains(addr2Num)) {
  458. addressNumSize--;
  459. if (addressNumSize == 0) {
  460. return contentBean1;
  461. }
  462. }
  463. }
  464. }
  465. }
  466. }
  467. }
  468. }
  469. }
  470. } else {
  471. return null;
  472. }
  473. }
  474. // 结果与基准数据完全一致,则使用。
  475. case LEVEL_TOTAL_CONTAINS_5: {
  476. if (result != null && result.getData() != null && result.getData().size() > 0) {
  477. List<AddressResult.ContentBean> contentBean = result.getData();
  478. for (AddressResult.ContentBean contentBean1 : contentBean) {
  479. if (contentBean1.getAddress() != null) {
  480. String address = addressReplaceAll(contentBean1.getAddress());
  481. String address2 = addressReplaceAll(addr);
  482. if (isNotEmptyOrBlank(address) && address.equals(address2)) {
  483. return contentBean1;
  484. }
  485. }
  486. }
  487. } else {
  488. return null;
  489. }
  490. }
  491. default: {
  492. return null;
  493. }
  494. }
  495. }
  496. public static String addressReplaceAll(String address) {
  497. return address.replaceAll("上海市", "").replaceAll(Constant.getArea() + "区", "").replaceAll("-", "").replaceAll("_", "").replaceAll("/", "").replaceAll(" ", "").replaceAll(",", "").replaceAll("\\.", "").replaceAll(",", "").replaceAll("。", "").replaceAll("\\+", "").replaceAll("\\*", "");
  498. }
  499. public static String townReplace_ct(String address) {
  500. address = address.replaceAll(" ", "");
  501. // 替换市
  502. address = address.replaceAll("上海市", "");
  503. String[] towns = Constant.getTowns();
  504. for (String town : towns) {
  505. if (address.contains(town)) {
  506. address = address.substring(address.indexOf(town) + town.length());
  507. }
  508. }
  509. // TODO 强行去除居委
  510. if (address.contains("居委会")) {
  511. address = address.substring(address.indexOf("居委会") + 3);
  512. }
  513. if (address.contains("委员会")) {
  514. address = address.substring(address.indexOf("委员会") + 3);
  515. }
  516. return address;
  517. }
  518. public static String townReplaceAll(String address) {
  519. address = townReplace_ct(address);
  520. return address.replaceAll("小区", "0").replaceAll("号", "0").replaceAll("弄", "0").replaceAll("室", "0").replaceAll("户", "0").replaceAll("单元", "0").replaceAll("幢", "0");
  521. }
  522. /**
  523. * 数字和文字分词返回List<Set<String>>
  524. *
  525. * @param input
  526. * @return
  527. */
  528. public static List<Set<String>> tokenizeString(String input) {
  529. // 初始化两个集合,一个用于存储非数字字符串,一个用于存储数字字符串
  530. Set<String> nonNumberSet = new HashSet<>();
  531. Set<String> numberSet = new HashSet<>();
  532. StringBuilder currentToken = new StringBuilder();
  533. for (int i = 0; i < input.length(); i++) {
  534. char c = input.charAt(i);
  535. if (Character.isDigit(c)) {
  536. // 如果当前字符是数字
  537. if (currentToken.length() > 0 && !Character.isDigit(currentToken.charAt(0))) {
  538. // 如果之前的 token 是非数字,将其添加到非数字集合中
  539. nonNumberSet.add(currentToken.toString());
  540. currentToken.setLength(0);
  541. }
  542. currentToken.append(c);
  543. } else {
  544. // 如果当前字符不是数字
  545. if (currentToken.length() > 0 && Character.isDigit(currentToken.charAt(0))) {
  546. // 如果之前的 token 是数字,将其添加到数字集合中
  547. numberSet.add(currentToken.toString());
  548. currentToken.setLength(0);
  549. }
  550. if (!Character.isWhitespace(c)) {
  551. currentToken.append(c);
  552. }
  553. }
  554. }
  555. // 处理最后一个 token
  556. if (currentToken.length() > 0) {
  557. if (Character.isDigit(currentToken.charAt(0))) {
  558. numberSet.add(currentToken.toString());
  559. } else {
  560. nonNumberSet.add(currentToken.toString());
  561. }
  562. }
  563. // 将两个集合添加到列表中
  564. List<Set<String>> result = new ArrayList<>();
  565. result.add(nonNumberSet);
  566. result.add(numberSet);
  567. return result;
  568. }
  569. }