本文目录导读:

在PHP项目中解析地址并拆分为省/市/区字段,常见有以下几种方案:
使用正则表达式(简单场景)
适用于格式比较规范的地址:
function parseAddress($address) {
$pattern = '/(?P<province>[^省]+省|新疆|西藏|内蒙古|广西|宁夏|北京|天津|上海|重庆)(?P<city>[^市]+市|自治州|地区|盟)(?P<district>[^区]+区|县|市|旗|自治县)/u';
preg_match($pattern, $address, $matches);
return [
'province' => $matches['province'] ?? '',
'city' => $matches['city'] ?? '',
'district' => $matches['district'] ?? '',
'detail' => str_replace([$matches['province'] ?? '', $matches['city'] ?? '', $matches['district'] ?? ''], '', $address)
];
}
// 使用示例
$address = "广东省广州市天河区天河路123号";
$result = parseAddress($address);
print_r($result);
基于行政区划字典库(推荐方案)
1 准备行政区划数据
// provinces.php - 省级数据
$provinces = [
'北京', '天津', '上海', '重庆',
'河北', '山西', '辽宁', '吉林',
'黑龙江', '江苏', '浙江', '安徽',
'福建', '江西', '山东', '河南',
'湖北', '湖南', '广东', '广西',
'海南', '四川', '贵州', '云南',
'西藏', '陕西', '甘肃', '青海',
'宁夏', '新疆', '台湾', '香港', '澳门'
];
// cities.php - 市级数据(部分示例)
$cities = [
'广州', '深圳', '珠海', '汕头',
'佛山', '韶关', '湛江', '肇庆',
// ... 完整数据可购买或使用公开数据集
];
2 实现解析函数
class AddressParser {
private $provinces;
private $provinceMap;
private $cityMap;
public function __construct() {
$this->provinces = [
'北京', '天津', '上海', '重庆',
'河北省', '山西省', '辽宁省',
// ... 完整数据
];
$this->initMaps();
}
private function initMaps() {
// 建立别名映射
$this->provinceMap = [
'北京' => '北京市', '上海' => '上海市',
'广东' => '广东省', '广州' => '广东省',
// ... 更多映射
];
$this->cityMap = [
'广州' => '广州市', '深圳' => '深圳市',
'北京区' => '北京市', // 部分特殊处理
];
}
public function parse($address) {
$result = [
'province' => '',
'city' => '',
'district' => '',
'detail' => $address
];
// 1. 提取省份
$result['province'] = $this->extractProvince($address);
// 2. 提取城市
$result['city'] = $this->extractCity($address, $result['province']);
// 3. 提取区县
$result['district'] = $this->extractDistrict($address);
// 4. 清理详细地址
$result['detail'] = $this->cleanDetail($address, $result);
return $result;
}
private function extractProvince($address) {
// 匹配"省"或特殊直辖市
foreach ($this->provinceMap as $keyword => $province) {
if (strpos($address, $keyword) !== false) {
return $province;
}
}
return '';
}
private function extractCity($address, $province = '') {
// 根据省份缩小范围查找
if ($province) {
// 从已知城市库中匹配
$cities = $this->getCitiesByProvince($province);
foreach ($cities as $city) {
if (strpos($address, $city) !== false) {
return $city;
}
}
}
// 通用匹配
$pattern = '/([^市]+市)/u';
preg_match($pattern, $address, $matches);
return $matches[1] ?? '';
}
private function extractDistrict($address) {
$pattern = '/([^区]+区|[^县]+县|[^市]+市)/u';
preg_match($pattern, $address, $matches);
return $matches[1] ?? '';
}
private function cleanDetail($address, $parsed) {
$replacements = array_filter([
$parsed['province'],
$parsed['city'],
$parsed['district']
]);
foreach ($replacements as $part) {
$address = str_replace($part, '', $address);
}
return trim($address);
}
}
// 使用示例
$parser = new AddressParser();
$address = "广东省广州市天河区体育西路123号";
$result = $parser->parse($address);
print_r($result);
使用第三方API服务(最准确)
class AddressApiParser {
private $apiKey;
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
public function parse($address) {
// 使用百度地图API示例
$url = "https://api.map.baidu.com/geocoding/v3/";
$params = [
'address' => $address,
'output' => 'json',
'ak' => $this->apiKey
];
$response = $this->curlGet($url, $params);
$data = json_decode($response, true);
if ($data['status'] == 0) {
$components = $data['result']['addressComponent'];
return [
'province' => $components['province'],
'city' => $components['city'],
'district' => $components['district'],
'detail' => str_replace(
[$components['province'], $components['city'], $components['district']],
'',
$address
)
];
}
return null;
}
private function curlGet($url, $params) {
$url .= '?' . http_build_query($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
// 使用示例
$apiKey = 'your_baidu_api_key';
$parser = new AddressApiParser($apiKey);
$result = $parser->parse("广东省广州市天河区体育西路123号");
综合推荐方案
class SmartAddressParser {
private $apiParser;
private $localParser;
public function __construct($apiKey = null) {
$this->localParser = new AddressParser();
if ($apiKey) {
$this->apiParser = new AddressApiParser($apiKey);
}
}
public function parse($address) {
// 优先使用本地解析(快速且无需API调用)
$result = $this->localParser->parse($address);
// 如果本地解析不完整,使用API
if (empty($result['province']) && $this->apiParser) {
$apiResult = $this->apiParser->parse($address);
if ($apiResult) {
$result = $apiResult;
}
}
return $result;
}
}
// 使用
$parser = new SmartAddressParser('your_api_key');
$addresses = [
"广东省广州市天河区天河路123号",
"北京市朝阳区建国路88号",
"上海市浦东新区陆家嘴金融贸易区"
];
foreach ($addresses as $address) {
$result = $parser->parse($address);
echo "原地址: {$address}\n";
echo "省: {$result['province']}\n";
echo "市: {$result['city']}\n";
echo "区: {$result['district']}\n";
echo "详细: {$result['detail']}\n\n";
}
注意事项
-
特殊地区处理:
- 直辖市(北京、上海等)
- 自治州、地区
- 省直辖县级市
- 新疆兵团等特殊行政区划
-
性能考虑:
- 本地解析快速但准确率较低
- API解析准确但依赖网络且可能有费用
-
数据更新:
- 行政区划会变动,需要定期更新数据
- 关注民政部发布的行政区划调整通知
建议根据项目需求选择合适的方案,对于电商、物流等对准确性要求高的场景,推荐使用API方案或结合字典库的混合方案。