PHP项目地址分词如何拆分省市区街道字段

wen PHP项目 26

本文目录导读:

PHP项目地址分词如何拆分省市区街道字段

  1. 使用正则表达式(简单场景)
  2. 使用地址分词库(推荐)
  3. 使用第三方API服务
  4. 完整的分词工具类
  5. 数据库方案
  6. 建议

在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;

建议

  1. 简单项目:使用正则表达式或自定义规则
  2. 中等项目:使用结巴分词 + 地址词典
  3. 高精度需求:使用高德、百度等地图API
  4. 考虑边界情况:直辖市、自治州、特殊地名等

选择哪种方案取决于你的具体需求、数据量和精度要求。

抱歉,评论功能暂时关闭!