chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace addon\haonav\library;
|
||||
|
||||
/**
|
||||
* 轻量拼音工具(零依赖)
|
||||
*
|
||||
* - 首字母:基于 GBK 编码区间推导(覆盖 GB2312 常用汉字),如「淘宝网」-> tbw
|
||||
* - 全拼:若安装了 overtrue/pinyin 则自动启用;未安装时降级为仅首字母
|
||||
* - keywordsOf() 产出「首字母 + 全拼」搜索串,存入 links.pinyin 供 LIKE 检索
|
||||
*/
|
||||
class Pinyin
|
||||
{
|
||||
/**
|
||||
* GBK 双字节码位 -> 拼音首字母 区间表(GB2312 一级/二级汉字按拼音排序的特性)
|
||||
* 每项:[起始码位, 结束码位, 字母]
|
||||
*/
|
||||
protected const RANGES = [
|
||||
[0xB0A1, 0xB0C4, 'a'],
|
||||
[0xB0C5, 0xB2C0, 'b'],
|
||||
[0xB2C1, 0xB4ED, 'c'],
|
||||
[0xB4EE, 0xB6E9, 'd'],
|
||||
[0xB6EA, 0xB7A1, 'e'],
|
||||
[0xB7A2, 0xB8C0, 'f'],
|
||||
[0xB8C1, 0xB9FD, 'g'],
|
||||
[0xB9FE, 0xBBF6, 'h'],
|
||||
[0xBBF7, 0xBFA5, 'j'],
|
||||
[0xBFA6, 0xC0AB, 'k'],
|
||||
[0xC0AC, 0xC2E7, 'l'],
|
||||
[0xC2E8, 0xC4C2, 'm'],
|
||||
[0xC4C3, 0xC5B5, 'n'],
|
||||
[0xC5B6, 0xC5BD, 'o'],
|
||||
[0xC5BE, 0xC6D9, 'p'],
|
||||
[0xC6DA, 0xC8BA, 'q'],
|
||||
[0xC8BB, 0xC8F5, 'r'],
|
||||
[0xC8F6, 0xCBF9, 's'],
|
||||
[0xCBFA, 0xCDD9, 't'],
|
||||
[0xCDDA, 0xCEF3, 'w'],
|
||||
[0xCEF4, 0xD1B8, 'x'],
|
||||
[0xD1B9, 0xD4D0, 'y'],
|
||||
[0xD4D1, 0xD7F9, 'z'],
|
||||
];
|
||||
|
||||
/**
|
||||
* 取单字符的拼音首字母;ASCII 字母数字原样小写返回,非汉字返回空串
|
||||
*/
|
||||
public static function firstLetter(string $char): string
|
||||
{
|
||||
if ($char === '') {
|
||||
return '';
|
||||
}
|
||||
if (preg_match('/^[a-zA-Z0-9]$/', $char)) {
|
||||
return strtolower($char);
|
||||
}
|
||||
$gbk = @iconv('UTF-8', 'GBK//IGNORE', $char);
|
||||
if ($gbk === false || strlen($gbk) < 2) {
|
||||
return '';
|
||||
}
|
||||
$code = ord($gbk[0]) * 256 + ord($gbk[1]);
|
||||
foreach (self::RANGES as [$min, $max, $letter]) {
|
||||
if ($code >= $min && $code <= $max) {
|
||||
return $letter;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 整串首字母:如「淘宝网」-> "tbw",「哔哩哔哩B站」-> "blblbz"
|
||||
*/
|
||||
public static function initials(string $str): string
|
||||
{
|
||||
$out = '';
|
||||
foreach (preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY) ?: [] as $ch) {
|
||||
$out .= self::firstLetter($ch);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全拼(依赖 overtrue/pinyin,未安装返回空串)
|
||||
*/
|
||||
public static function full(string $str): string
|
||||
{
|
||||
if (!class_exists(\Overtrue\Pinyin\Pinyin::class)) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
// v5 静态 API
|
||||
if (method_exists(\Overtrue\Pinyin\Pinyin::class, 'sentence')) {
|
||||
$r = \Overtrue\Pinyin\Pinyin::sentence($str);
|
||||
$s = is_object($r) && method_exists($r, 'join') ? $r->join('') : (string)$r;
|
||||
return preg_replace('/[^a-z0-9]/', '', strtolower($s)) ?? '';
|
||||
}
|
||||
// v4 实例 API
|
||||
$py = new \Overtrue\Pinyin\Pinyin();
|
||||
return preg_replace('/[^a-z0-9]/', '', strtolower(implode('', $py->convert($str)))) ?? '';
|
||||
} catch (\Throwable $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成搜索串:「首字母 全拼」(全拼可能为空),限长 250
|
||||
*/
|
||||
public static function keywordsOf(string $str): string
|
||||
{
|
||||
$initials = self::initials($str);
|
||||
$full = self::full($str);
|
||||
$out = trim($initials . ($full !== '' && $full !== $initials ? ' ' . $full : ''));
|
||||
return mb_substr($out, 0, 250);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user