本文目录导读:

在PHP项目中拆分省市区街道地址,有几种常见的方法:
使用正则表达式(简单场景)
function splitAddress($address) {
$pattern = '/(?<province>[^省]+省|[^自治区]+自治区|北京|天津|上海|重庆)';
$pattern .= '(?<city>[^市]+市|[^自治州]+自治州|地区|区划)';
$pattern .= '(?<district>[^区]+区|[^县]+县|[^旗]+旗)';
$pattern .= '(?<street>.+)?/';
preg_match($pattern, $address, $matches);
return [
'province' => $matches['province'] ?? '',
'city' => $matches['city'] ?? '',
'district' => $matches['district'] ?? '',
'street' => $matches['street'] ?? ''
];
}
使用地址分词库(推荐)
安装 jieba-php(如果是纯PHP项目)
composer require fukuball/jieba-php
使用示例
require_once '/path/to/vendor/autoload.php';
use Fukuball\Jieba\Jieba;
use Fukuball\Jieba\Finalseg;
class AddressParser {
private $jieba;
private $provinceCityDict;
public function __construct() {
Jieba::init();
Finalseg::init();
// 预加载省市区词典
$this->provinceCityDict = $this->loadAddressDictionary();
}
private function loadAddressDictionary() {
return [
'provinces' => ['北京', '天津', '上海', '重庆', '河北省', '山西省', ...],
'cities' => ['石家庄市', '唐山市', '秦皇岛市', ...],
'districts' => ['长安区', '桥西区', '新华区', ...]
];
}
public function parse($address) {
$segments = Jieba::cut($address, true);
$result = [
'province' => '',
'city' => '',
'district' => '',
'street' => ''
];
foreach ($segments as $segment) {
if ($this->isProvince($segment)) {
$result['province'] = $segment;
} elseif ($this->isCity($segment)) {
$result['city'] = $segment;
} elseif ($this->isDistrict($segment)) {
$result['district'] = $segment;
} else {
$result['street'] .= $segment;
}
}
return $result;
}
}
使用第三方API服务
高德地图API
function parseAddressWithAMap($address) {
$apiKey = 'your_api_key';
$url = "https://restapi.amap.com/v3/geocode/geo?key={$apiKey}&address=" . urlencode($address);
$response = file_get_contents($url);
$data = json_decode($response, true);
if ($data['status'] == '1' && !empty($data['geocodes'])) {
$geocode = $data['geocodes'][0];
return [
'province' => $geocode['province'] ?? '',
'city' => $geocode['city'] ?? '',
'district' => $geocode['district'] ?? '',
'formatted_address' => $geocode['formatted_address'] ?? ''
];
}
return null;
}
完整的分词工具类
class AddressSplitter {
private $provinceKeywords = ['省', '自治区', '直辖市'];
private $cityKeywords = ['市', '自治州', '地区'];
private $districtKeywords = ['区', '县', '县级市', '旗'];
public function split($address) {
$address = trim($address);
// 处理直辖市
if ($this->isMunicipality($address)) {
return $this->handleMunicipality($address);
}
$result = [
'province' => '',
'city' => '',
'district' => '',
'street' => $address
];
// 提取省份
$provinceEnd = $this->findKeywordEnd($address, $this->provinceKeywords);
if ($provinceEnd !== false) {
$result['province'] = substr($address, 0, $provinceEnd);
$address = substr($address, $provinceEnd);
}
// 提取城市
$cityEnd = $this->findKeywordEnd($address, $this->cityKeywords);
if ($cityEnd !== false) {
$result['city'] = substr($address, 0, $cityEnd);
$address = substr($address, $cityEnd);
}
// 提取区县
$districtEnd = $this->findKeywordEnd($address, $this->districtKeywords);
if ($districtEnd !== false) {
$result['district'] = substr($address, 0, $districtEnd);
$address = substr($address, $districtEnd);
}
$result['street'] = trim($address);
return $result;
}
private function findKeywordEnd($text, $keywords) {
foreach ($keywords as $keyword) {
$pos = mb_strpos($text, $keyword);
if ($pos !== false) {
return $pos + mb_strlen($keyword);
}
}
return false;
}
private function isMunicipality($address) {
$municipalities = ['北京', '天津', '上海', '重庆'];
foreach ($municipalities as $municipality) {
if (mb_strpos($address, $municipality) === 0) {
return true;
}
}
return false;
}
private function handleMunicipality($address) {
$result = [
'province' => '',
'city' => '',
'district' => '',
'street' => ''
];
// 提取直辖市名称
if (mb_strpos($address, '北京市') === 0) {
$result['province'] = '北京市';
$result['city'] = '北京市';
$address = substr($address, 9); // 去掉"北京市"
} elseif (mb_strpos($address, '天津市') === 0) {
// 类似处理
}
// ... 处理其他直辖市
return $result;
}
}
// 使用示例
$splitter = new AddressSplitter();
$address = "河北省石家庄市长安区中山路100号";
$result = $splitter->split($address);
print_r($result);
数据库方案
创建地址词典表并查询:
CREATE TABLE address_dictionary (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
level ENUM('province', 'city', 'district', 'street') NOT NULL,
parent_id INT DEFAULT NULL
);
-- 查询示例
SELECT name FROM address_dictionary
WHERE level = 'province'
AND POSITION(name IN ?) > 0;
建议
- 简单项目:使用正则表达式或自定义规则
- 中等项目:使用结巴分词 + 地址词典
- 高精度需求:使用高德、百度等地图API
- 考虑边界情况:直辖市、自治州、特殊地名等
选择哪种方案取决于你的具体需求、数据量和精度要求。