本文目录导读:

我来给你提供几种PHP拼音搜索的解决方案,从简单到复杂都有:
最简方案:使用拼音数据库(推荐)
安装方式
composer require overtrue/pinyin
核心实现代码
<?php
use Overtrue\Pinyin\Pinyin;
class PinyinSearch
{
private $pinyin;
public function __construct()
{
$this->pinyin = new Pinyin();
}
/**
* 将中文转拼音
*/
public function toPinyin($text)
{
// 获取全拼
$full = $this->pinyin->convert($text);
// 获取首字母
$abbr = $this->pinyin->abbr($text);
return [
'full' => implode('', $full), // 全拼无空格
'full_space' => implode(' ', $full), // 全拼带空格
'abbr' => $abbr, // 首字母
];
}
/**
* 搜索方法 - 支持拼音和中文混合搜索
*/
public function search($keywords, $data)
{
$results = [];
$kwPinyin = $this->toPinyin($keywords);
foreach ($data as $item) {
$itemPinyin = $this->toPinyin($item['name']);
// 多种匹配方式
if (strpos($itemPinyin['full'], $keywords) !== false || // 直接匹配中文
strpos($itemPinyin['full'], $kwPinyin['full']) !== false || // 匹配全拼
strpos($itemPinyin['abbr'], $kwPinyin['abbr']) !== false || // 匹配首字母
$this->fuzzyMatch($keywords, $itemPinyin)) { // 模糊匹配
$results[] = $item;
}
}
return $results;
}
/**
* 模糊匹配(支持拼音简拼和全拼混合)
*/
private function fuzzyMatch($keyword, $pinyinData)
{
$keyword = strtolower($keyword);
$full = strtolower($pinyinData['full']);
$abbr = strtolower($pinyinData['abbr']);
// 简拼+全拼混合,如 "北京欢迎你" -> "bjhyn"
if (preg_match('/^[a-z]+$/', $keyword)) {
// 全字母匹配
if (strpos($full, $keyword) !== false) return true;
// 首字母匹配
if (strpos($abbr, $keyword) !== false) return true;
// 混合匹配:部分全拼+部分简拼
$pattern = '';
foreach (str_split($keyword) as $char) {
$pattern .= $char . '.*';
}
if (preg_match('/' . $pattern . '/', $full)) return true;
}
return false;
}
}
// 使用示例
$search = new PinyinSearch();
$data = [
['id' => 1, 'name' => '北京欢迎你'],
['id' => 2, 'name' => '上海迪士尼'],
['id' => 3, 'name' => '广州长隆'],
['id' => 4, 'name' => '深圳世界之窗'],
];
// 搜索 "北京" 或 "bj" 或 "北京hyn"
$results = $search->search('bj', $data);
print_r($results);
MySQL全文索引方案(大数据量)
数据库表结构设计
-- 创建拼音字段表 CREATE TABLE `products` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `pinyin` varchar(255) DEFAULT NULL, -- 全拼 `pinyin_abbr` varchar(50) DEFAULT NULL, -- 首字母 PRIMARY KEY (`id`), KEY `idx_pinyin` (`pinyin`), KEY `idx_pinyin_abbr` (`pinyin_abbr`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
PHP实现
<?php
class PinyinFullTextSearch
{
private $pdo;
private $pinyin;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
$this->pinyin = new Pinyin();
}
/**
* 数据插入时同步拼音
*/
public function addProduct($name)
{
$pinyin = $this->pinyin->convert($name);
$abbr = $this->pinyin->abbr($name);
$stmt = $this->pdo->prepare(
"INSERT INTO products (name, pinyin, pinyin_abbr)
VALUES (?, ?, ?)"
);
$stmt->execute([
$name,
implode('', $pinyin),
$abbr
]);
return $this->pdo->lastInsertId();
}
/**
* 高效拼音搜索 - SQL查询
*/
public function search($keyword)
{
// 将关键词转为拼音
$pinyinKeyword = $this->pinyin->convert($keyword);
$abbrKeyword = $this->pinyin->abbr($keyword);
$sql = "SELECT * FROM products
WHERE
name LIKE :keyword OR
pinyin LIKE :pinyin OR
pinyin_abbr LIKE :abbr
ORDER BY
CASE
WHEN name LIKE :keyword_exact THEN 1
WHEN pinyin LIKE :pinyin_exact THEN 2
WHEN pinyin_abbr LIKE :abbr_exact THEN 3
ELSE 4
END
LIMIT 20";
$stmt = $this->pdo->prepare($sql);
$like = '%' . $keyword . '%';
$likePinyin = '%' . implode('', $pinyinKeyword) . '%';
$likeAbbr = '%' . $abbrKeyword . '%';
$stmt->execute([
'keyword' => $like,
'pinyin' => $likePinyin,
'abbr' => $likeAbbr,
'keyword_exact' => $keyword . '%',
'pinyin_exact' => implode('', $pinyinKeyword) . '%',
'abbr_exact' => $abbrKeyword . '%'
]);
return $stmt->fetchAll();
}
}
Redis缓存方案(高性能)
<?php
class PinyinRedisSearch
{
private $redis;
private $pinyin;
public function __construct(Redis $redis)
{
$this->redis = $redis;
$this->pinyin = new Pinyin();
}
/**
* 初始化拼音索引
*/
public function buildIndex($products)
{
foreach ($products as $product) {
$pinyin = $this->pinyin->convert($product['name']);
$abbr = $this->pinyin->abbr($product['name']);
// 建立索引
$this->redis->sAdd('pinyin:' . implode('', $pinyin), $product['id']);
$this->redis->sAdd('pinyin_abbr:' . $abbr, $product['id']);
$this->redis->sAdd('pinyin_space:' . implode(' ', $pinyin), $product['id']);
// 建立模糊索引(每个拼音前缀)
$fullPinyin = implode('', $pinyin);
for ($i = 1; $i <= strlen($fullPinyin); $i++) {
$prefix = substr($fullPinyin, 0, $i);
$this->redis->sAdd('pinyin_prefix:' . $prefix, $product['id']);
}
}
}
/**
* 快速搜索
*/
public function search($keyword)
{
if (preg_match('/[\x{4e00}-\x{9fa5}]/u', $keyword)) {
// 中文搜索
$ids = $this->redis->sInter('pinyin:' . $this->pinyin->convert($keyword));
} else {
// 拼音搜索
$ids = $this->redis->sMembers('pinyin_prefix:' . strtolower($keyword));
}
// 获取产品信息
$products = [];
foreach ($ids as $id) {
$products[] = $this->getProductById($id);
}
return $products;
}
}
前端+后端配合方案
PHP后端返回拼音数据
<?php
// 返回含有拼音的数据
public function getProductsWithPinyin()
{
$products = $this->getAllProducts();
foreach ($products as &$product) {
$pinyin = $this->pinyin->convert($product['name']);
$product['pinyin'] = implode('', $pinyin);
$product['pinyin_abbr'] = $this->pinyin->abbr($product['name']);
$product['pinyin_array'] = $pinyin; // 每个字对应的拼音
}
return json_encode($products);
}
前端JavaScript实现实时搜索
// search.js
class PinyinSearchBox {
constructor(data) {
this.data = data;
this.init();
}
init() {
this.searchInput.addEventListener('input', (e) => {
const keyword = e.target.value.toLowerCase();
this.filterData(keyword);
});
}
filterData(keyword) {
if (!keyword) {
this.renderAll();
return;
}
const results = this.data.filter(item => {
// 中文匹配
if (item.name.includes(keyword)) return true;
// 拼音匹配
if (item.pinyin.includes(keyword)) return true;
// 首字母匹配
if (item.pinyin_abbr.includes(keyword)) return true;
// 拼音首字母与汉字混合匹配
const keywordArray = keyword.split('');
let pinyinIndex = 0;
let nameIndex = 0;
while (nameIndex < item.name.length && pinyinIndex < keywordArray.length) {
// 检查是否为汉字
if (/[\u4e00-\u9fa5]/.test(keywordArray[pinyinIndex])) {
if (item.name[nameIndex] === keywordArray[pinyinIndex]) {
pinyinIndex++;
}
nameIndex++;
} else {
// 拼音匹配
const pinyinChar = item.pinyin_array[nameIndex] || '';
if (pinyinChar.startsWith(keywordArray[pinyinIndex])) {
pinyinIndex++;
nameIndex++;
} else {
return false;
}
}
}
return pinyinIndex === keywordArray.length;
});
this.renderResults(results);
}
}
Elasticsearch搜索方案(企业级)
<?php
// 使用Elasticsearch
use Elastic\Elasticsearch\ClientBuilder;
class ElasticPinyinSearch
{
private $client;
public function __construct()
{
$this->client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
}
/**
* 创建索引(带拼音分析器)
*/
public function createIndex()
{
$params = [
'index' => 'products',
'body' => [
'settings' => [
'analysis' => [
'analyzer' => [
'pinyin_analyzer' => [
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => ['pinyin_filter']
]
],
'filter' => [
'pinyin_filter' => [
'type' => 'pinyin',
'keep_full_pinyin' => true,
'keep_first_letter' => true,
'keep_joined_full_pinyin' => true
]
]
]
],
'mappings' => [
'properties' => [
'name' => [
'type' => 'text',
'analyzer' => 'pinyin_analyzer',
'search_analyzer' => 'standard'
]
]
]
]
];
return $this->client->indices()->create($params);
}
/**
* 拼音搜索
*/
public function search($keyword)
{
$params = [
'index' => 'products',
'body' => [
'query' => [
'multi_match' => [
'query' => $keyword,
'fields' => ['name^3', 'name.pinyin']
]
],
'highlight' => [
'fields' => [
'name' => ['pre_tags' => ['<b>'], 'post_tags' => ['</b>']]
]
]
]
];
return $this->client->search($params);
}
}
建议
- 小项目:使用
overtrue/pinyin包,简单易用 - 中型项目:数据库添加拼音字段 + 索引
- 大型项目:Elasticsearch + IK分析器 + 拼音插件
- 高并发:Redis缓存 + 拼音索引
需要哪种具体方案的完整实现,或者有特定的使用场景,可以详细说说。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播