// +---------------------------------------------------------------------- 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); } }