AddressParseHelper.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. namespace common\helpers\AddressParse;
  3. class AddressParseHelper
  4. {
  5. /*
  6. ** 智能解析
  7. */
  8. public static function smart($string, $user = true)
  9. {
  10. if ($user) {
  11. $decompose = self::decompose($string);
  12. $re = $decompose;
  13. } else {
  14. $re['addr'] = $string;
  15. }
  16. $fuzz = self::fuzz($re['addr']);
  17. $parse = self::parse($fuzz['a1'], $fuzz['a2'], $fuzz['a3']);
  18. $re['province'] = $parse['province'];
  19. $re['city'] = $parse['city'];
  20. $re['area'] = $parse['region'];
  21. $re['detail'] = ($fuzz['street']) ? $fuzz['street'] : '';
  22. $re['detail'] = str_replace([$re['area'], $re['city'], $re['province']], ['', '', ''], $re['detail']);
  23. return $re;
  24. }
  25. /*
  26. ** 分离手机号(座机),身份证号,姓名等用户信息
  27. */
  28. public static function decompose($string)
  29. {
  30. $compose = array();
  31. $search = array('收货地址', '详细地址', '地址', '收货人', '收件人', '收货', '所在地区', '邮编', '电话', '手机号', '手机', '手机号码','身份证号码', '身份证号', '身份证', ':', ':', ';', ';', ',', ',', '。');
  32. $replace = array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
  33. $string = str_replace($search, $replace, $string);
  34. $string = preg_replace('/\s{1,}/', ' ', $string);
  35. $string = preg_replace('/0?(\d{3})-(\d{4})-(\d{4})([-_]\d{1,})/', '$1$2$3$4', $string);
  36. preg_match('/\d{18}|\d{17}X/i', $string, $match);
  37. if ($match && $match[0]) {
  38. $compose['idn'] = strtoupper($match[0]);
  39. $string = str_replace($match[0], '', $string);
  40. }
  41. preg_match('/\d{7,11}[\-_]\d{2,6}|\d{7,11}|\d{3,4}-\d{6,8}/', $string, $match);
  42. if ($match && $match[0]) {
  43. $compose['mobile'] = $match[0];
  44. $string = str_replace($match[0], '', $string);
  45. }
  46. preg_match('/\d{6}/', $string, $match);
  47. if ($match && $match[0]) {
  48. $compose['postcode'] = $match[0];
  49. $string = str_replace($match[0], '', $string);
  50. }
  51. $string = trim(preg_replace('/ {2,}/', ' ', $string));
  52. $split_arr = explode(' ', $string);
  53. if (count($split_arr) > 1) {
  54. $compose['name'] = $split_arr[0];
  55. foreach ($split_arr as $value) {
  56. if (strlen($value) < strlen($compose['name'])) {
  57. $compose['name'] = $value;
  58. }
  59. }
  60. $string = trim(str_replace($compose['name'], '', $string));
  61. }
  62. $compose['addr'] = $string;
  63. return $compose;
  64. }
  65. /*
  66. ** 根据统计规律分析出二三级地址
  67. */
  68. public static function fuzz($addr)
  69. {
  70. //$addr_origin = $addr;
  71. $addr = str_replace([' ', ','], ['', ''], $addr);
  72. $addr_origin = $addr;
  73. $addr = str_replace('自治区', '省', $addr);
  74. $addr = str_replace('自治州', '州', $addr);
  75. $addr = str_replace('小区', '', $addr);
  76. $addr = str_replace('校区', '', $addr);
  77. $a1 = '';
  78. $a2 = '';
  79. $a3 = '';
  80. $street = '';
  81. $isSpecial = 0; //是否作特殊处理
  82. if (
  83. mb_strpos($addr, '县') !== false && mb_strpos($addr, '县') <= floor((mb_strlen($addr) / 3) * 2)
  84. || (mb_strpos($addr, '区') !== false && mb_strpos($addr, '区') <= floor((mb_strlen($addr) / 3) * 2))
  85. || (mb_strpos($addr, '镇') !== false && mb_strpos($addr, '镇') <= floor((mb_strlen($addr) / 3) * 2))
  86. || mb_strpos($addr, '旗') !== false && mb_strpos($addr, '旗') <= floor((mb_strlen($addr) / 3) * 2))
  87. {
  88. if (mb_strstr($addr, '旗')) {
  89. $deep3_keyword_pos = mb_strpos($addr, '旗');
  90. $a3 = mb_substr($addr, $deep3_keyword_pos - 1, 2);
  91. }
  92. if (mb_strstr($addr, '镇')) {
  93. $deep3_keyword_pos = mb_strpos($addr, '镇');
  94. if (mb_strstr($addr, '市')) {
  95. $city_pos = mb_strpos($addr, '市');
  96. $zone_pos = mb_strpos($addr, '镇');
  97. // liuzhantao:为了应对 “浙江省嘉兴市桐乡市崇福镇建业北路星东金街104号” 这种抠门地址,地址中有两个“市”,就会识别错误,需要特殊处理,下面六行代码:
  98. $first_city_pos = mb_strpos($addr, '市'); // 找到第一个 "市" 的位置
  99. $second_city_pos = mb_strpos($addr, '市', $first_city_pos + 1); // 试图找到第二个 "市",从第一个 "市" 的下一个字符开始查找
  100. if($second_city_pos !== false){ // 如果找到了第二个 "市",则使用它的位置,否则使用第一个 "市" 的位置
  101. $zone_pos = mb_strpos($addr, '镇') - 3;
  102. $isSpecial = 1;
  103. }
  104. $a3 = mb_substr($addr, $city_pos + 1, $zone_pos - $city_pos);
  105. } else {
  106. $a3 = mb_substr($addr, $deep3_keyword_pos - 2, 3);
  107. }
  108. }
  109. if (mb_strstr($addr, '区')) {
  110. $deep3_keyword_pos = mb_strpos($addr, '区');
  111. if (mb_strstr($addr, '市')) {
  112. $city_pos = mb_strpos($addr, '市');
  113. $zone_pos = mb_strpos($addr, '区');
  114. $a3 = mb_substr($addr, $city_pos + 1, $zone_pos - $city_pos);
  115. } else {
  116. $a3 = mb_substr($addr, $deep3_keyword_pos - 2, 3);
  117. }
  118. }
  119. if (mb_strstr($addr, '县')) {
  120. $deep3_keyword_pos = mb_strpos($addr, '县');
  121. if (mb_strstr($addr, '市')) {
  122. $city_pos = mb_strpos($addr, '市');
  123. $zone_pos = mb_strpos($addr, '县');
  124. $a3 = mb_substr($addr, $city_pos + 1, $zone_pos - $city_pos);
  125. } else {
  126. if (mb_strstr($addr, '自治县')) {
  127. $a3 = mb_substr($addr, $deep3_keyword_pos - 6, 7);
  128. if (in_array(mb_substr($a3, 0, 1), ['省', '市', '州'])) {
  129. $a3 = mb_substr($a3, 1);
  130. }
  131. } else {
  132. $a3 = mb_substr($addr, $deep3_keyword_pos - 2, 3);
  133. }
  134. }
  135. }
  136. if($isSpecial == 0){ // 不是特殊处理,地址照旧
  137. $street = mb_substr($addr_origin, $deep3_keyword_pos + 1);
  138. }else{ // 特殊处理
  139. $street = mb_substr($addr_origin, $deep3_keyword_pos - 2);
  140. }
  141. } else {
  142. if (mb_strripos($addr, '市')) {
  143. if (mb_substr_count($addr, '市') == 1) {
  144. $deep3_keyword_pos = mb_strripos($addr, '市');
  145. $a3 = mb_substr($addr, $deep3_keyword_pos - 2, 3);
  146. $street = mb_substr($addr_origin, $deep3_keyword_pos + 1);
  147. } else if (mb_substr_count($addr, '市') >= 2) {
  148. $deep3_keyword_pos = mb_strripos($addr, '市');
  149. $a3 = mb_substr($addr, $deep3_keyword_pos - 2, 3);
  150. $street = mb_substr($addr_origin, $deep3_keyword_pos + 1);
  151. }
  152. } else {
  153. $a3 = '';
  154. $street = $addr;
  155. }
  156. }
  157. if (mb_strpos($addr, '市') || mb_strstr($addr, '盟') || mb_strstr($addr, '州')) {
  158. if ($tmp_pos = mb_strpos($addr, '市')) {
  159. $a2 = mb_substr($addr, $tmp_pos - 2, 3);
  160. } else if ($tmp_pos = mb_strpos($addr, '盟')) {
  161. $a2 = mb_substr($addr, $tmp_pos - 2, 3);
  162. } else if ($tmp_pos = mb_strpos($addr, '州')) {
  163. if ($tmp_pos = mb_strpos($addr, '自治州')) {
  164. $a2 = mb_substr($addr, $tmp_pos - 4, 5);
  165. } else {
  166. $a2 = mb_substr($addr, $tmp_pos - 2, 3);
  167. }
  168. }
  169. } else {
  170. $a2 = '';
  171. }
  172. $a2;
  173. $r = array(
  174. 'a1' => $a1,
  175. 'a2' => $a2,
  176. 'a3' => $a3,
  177. 'street' => $street,
  178. );
  179. return $r;
  180. }
  181. /*
  182. ** 智能解析出省市区+街道地址
  183. */
  184. public static function parse($a1, $a2, $a3)
  185. {
  186. require 'data/area.php';
  187. require 'data/city.php';
  188. require 'data/province.php';
  189. $r = array();
  190. if ($a3 != '') {
  191. $area3_matches = array();
  192. foreach ($a3_data as $id => $v) {
  193. if (mb_strpos($v['name'], $a3) !== false) {
  194. $area3_matches[$id] = $v;
  195. }
  196. }
  197. if ($area3_matches && count($area3_matches) > 1) {
  198. if ($a2) {
  199. foreach ($a2_data as $id => $v) {
  200. if (mb_strpos($v['name'], $a2) !== false) {
  201. $area2_matches[$id] = $v;
  202. }
  203. }
  204. if ($area2_matches) {
  205. foreach ($area3_matches as $id => $v) {
  206. if (isset($area2_matches[$v['pid']])) {
  207. $r['city'] = $area2_matches[$v['pid']]['name'];
  208. $r['region'] = $v['name'];
  209. $sheng_id = $area2_matches[$v['pid']]['pid'];
  210. $r['province'] = $a1_data[$sheng_id]['name'];
  211. }
  212. }
  213. }
  214. } else {
  215. $r['province'] = '';
  216. $r['city'] = '';
  217. $r['region'] = $a3;
  218. }
  219. } else if ($area3_matches && count($area3_matches) == 1) {
  220. foreach ($area3_matches as $id => $v) {
  221. $city_id = $v['pid'];
  222. $r['region'] = $v['name'];
  223. }
  224. $city = $a2_data[$city_id];
  225. $province = $a1_data[$city['pid']];
  226. $r['province'] = $province['name'];
  227. $r['city'] = $city['name'];
  228. } else if (empty($area3_matches) && $a2 == $a3) {
  229. foreach ($a2_data as $id => $v) {
  230. if (mb_strpos($v['name'], $a2) !== false) {
  231. $area2_matches[$id] = $v;
  232. $sheng_id = $v['pid'];
  233. $r['city'] = $v['name'];
  234. }
  235. }
  236. $r['province'] = $a1_data[$sheng_id]['name'];
  237. $r['region'] = '';
  238. }
  239. }
  240. return $r;
  241. }
  242. }