parseAddress.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /**
  2. * 地址解析工具 - 使用关键词匹配方式解析省市区地址
  3. * 思路:通过省市区关键词截取,去两边留中间
  4. */
  5. /**
  6. * 解析连续文本格式的地址
  7. * @param {string} fullAddress 完整地址字符串,如:山西省太原市迎泽区庙前街道劲松北路9号院
  8. * @returns {Object|null} 解析后的地址信息
  9. */
  10. export const parseAddress = (fullAddress) => {
  11. if (!fullAddress || typeof fullAddress !== 'string') {
  12. console.warn('地址不能为空且必须为字符串');
  13. return null;
  14. }
  15. // 定义省市区关键词
  16. const provinceKeywords = /省|自治区|特别行政区/;
  17. const cityKeywords = /市|自治州|地区|盟/;
  18. const districtKeywords = /区|县|旗|自治县|自治旗|特区|林区/;
  19. // 1. 解析省份
  20. const provinceEndIndex = fullAddress.search(provinceKeywords);
  21. if (provinceEndIndex === -1) {
  22. // 处理直辖市情况
  23. const cityStartIndex = fullAddress.search(cityKeywords);
  24. if (cityStartIndex === -1) {
  25. console.warn('无法识别省份或城市');
  26. return null;
  27. }
  28. // 直辖市情况:如北京市海淀区
  29. const province = fullAddress.substring(0, cityStartIndex + 1);
  30. const city = province;
  31. // 解析区县
  32. const districtEndIndex = fullAddress.search(districtKeywords);
  33. if (districtEndIndex === -1) {
  34. console.warn('无法识别区县');
  35. return null;
  36. }
  37. const district = fullAddress.substring(city.length, districtEndIndex + 1);
  38. const street = fullAddress.substring(districtEndIndex + 1).trim();
  39. return {
  40. province,
  41. city,
  42. district,
  43. street: street || undefined
  44. };
  45. }
  46. // 2. 解析城市
  47. const province = fullAddress.substring(0, provinceEndIndex + 1);
  48. const remainingAfterProvince = fullAddress.substring(provinceEndIndex + 1);
  49. const cityEndIndex = remainingAfterProvince.search(cityKeywords);
  50. if (cityEndIndex === -1) {
  51. console.warn('无法识别城市');
  52. return null;
  53. }
  54. const city = remainingAfterProvince.substring(0, cityEndIndex + 1);
  55. const remainingAfterCity = remainingAfterProvince.substring(cityEndIndex + 1);
  56. // 3. 解析区县
  57. const districtEndIndex = remainingAfterCity.search(districtKeywords);
  58. if (districtEndIndex === -1) {
  59. console.warn('无法识别区县');
  60. return null;
  61. }
  62. const district = remainingAfterCity.substring(0, districtEndIndex + 1);
  63. const street = remainingAfterCity.substring(districtEndIndex + 1).trim();
  64. return {
  65. province,
  66. city,
  67. district,
  68. street: street || undefined
  69. };
  70. };
  71. /**
  72. * 仅获取省份名称
  73. * @param {string} fullAddress 完整地址字符串
  74. * @returns {string|null} 省份名称
  75. */
  76. export const getProvince = (fullAddress) => {
  77. const result = parseAddress(fullAddress);
  78. return result?.province || null;
  79. };
  80. /**
  81. * 仅获取城市名称
  82. * @param {string} fullAddress 完整地址字符串
  83. * @returns {string|null} 城市名称
  84. */
  85. export const getCity = (fullAddress) => {
  86. const result = parseAddress(fullAddress);
  87. return result?.city || null;
  88. };
  89. /**
  90. * 仅获取区县名称
  91. * @param {string} fullAddress 完整地址字符串
  92. * @returns {string|null} 区县名称
  93. */
  94. export const getDistrict = (fullAddress) => {
  95. const result = parseAddress(fullAddress);
  96. return result?.district || null;
  97. };
  98. /**
  99. * 获取解析后的省市区数组(用于回显)
  100. * @param {string} fullAddress 完整地址字符串
  101. * @returns {Array} 省市区数组
  102. */
  103. export const getAddressTree = (fullAddress) => {
  104. const result = parseAddress(fullAddress);
  105. if (!result) return [];
  106. return [result.province, result.city, result.district];
  107. };
  108. /**
  109. * 递归查找城市名称对应的areaCode
  110. * @param {string} cityName 城市名称
  111. * @param {Array} areaTree 省市区联级列表数据
  112. * @returns {string} 匹配到的areaCode,匹配不到返回空字符串
  113. */
  114. export const findCityCodeByCname = (cityName, areaTree) => {
  115. // 边界条件检查
  116. if (!cityName || !areaTree || !Array.isArray(areaTree)) {
  117. return '';
  118. }
  119. // 遍历当前层级
  120. for (const area of areaTree) {
  121. // 匹配到城市名称,返回areaCode
  122. if (area.areaCname == cityName) {
  123. return area.areaCode;
  124. }
  125. // 如果有子节点,递归查找
  126. if (area.children && area.children.length > 0) {
  127. const foundCode = findCityCodeByCname(cityName, area.children);
  128. if (foundCode) {
  129. return foundCode;
  130. }
  131. }
  132. }
  133. // 所有节点都遍历完,没有匹配到
  134. return '';
  135. };
  136. // Vue 2 插件形式
  137. const AddressParserPlugin = {
  138. install(Vue) {
  139. Vue.prototype.$parseAddress = parseAddress;
  140. Vue.prototype.$getProvince = getProvince;
  141. Vue.prototype.$getCity = getCity;
  142. Vue.prototype.$getDistrict = getDistrict;
  143. Vue.prototype.$getAddressTree = getAddressTree;
  144. Vue.prototype.$findCityCodeByCname = findCityCodeByCname;
  145. }
  146. };
  147. // 如果是在浏览器环境下直接使用
  148. if (typeof window !== 'undefined' && window.Vue) {
  149. window.Vue.use(AddressParserPlugin);
  150. }
  151. // 导出插件形式
  152. export default AddressParserPlugin;