PHP实现特殊格式Unicode字符串转普通文本(保留特殊字符)
解决方案:将数学字体文本转换为普通文本并保留特殊字符
核心思路
数学字体的字母(如𝐴、𝑙这类)属于Unicode的数学符号区块,与普通拉丁字母存在固定的Unicode码点偏移。我们可以通过匹配这些字符的范围,计算出对应的普通字符码点,同时保留原本的特殊字符(á、é、í、ó、ú、ñ、ç等不在数学字体区块内,不会被处理)。
PHP实现代码
function convertMathFontToNormal($str) { // 若输入为URL编码字符串,先解码 $str = rawurldecode($str); // 匹配常见数学字体字母的Unicode范围:斜体、加粗、加粗斜体的大小写字母 $mathCharPattern = '/[\x{1D400}-\x{1D419}\x{1D41A}-\x{1D433}\x{1D434}-\x{1D44D}\x{1D44E}-\x{1D467}\x{1D468}-\x{1D481}\x{1D482}-\x{1D49B}]/u'; return preg_replace_callback($mathCharPattern, function($matches) { $char = $matches[0]; $codePoint = mb_ord($char, 'UTF-8'); // 根据不同数学字体区块计算对应普通字符的码点 if ($codePoint >= 0x1D400 && $codePoint <= 0x1D419) { // 数学斜体大写字母 → 普通大写字母 $normalCode = $codePoint - 0x1D3BF; } elseif ($codePoint >= 0x1D41A && $codePoint <= 0x1D433) { // 数学斜体小写字母 → 普通小写字母 $normalCode = $codePoint - 0x1D3B9; } elseif ($codePoint >= 0x1D434 && $codePoint <= 0x1D44D) { // 数学加粗大写字母 → 普通大写字母 $normalCode = $codePoint - 0x1D3F3; } elseif ($codePoint >= 0x1D44E && $codePoint <= 0x1D467) { // 数学加粗小写字母 → 普通小写字母 $normalCode = $codePoint - 0x1D3ED; } elseif ($codePoint >= 0x1D468 && $codePoint <= 0x1D481) { // 数学加粗斜体大写字母 → 普通大写字母 $normalCode = $codePoint - 0x1D427; } elseif ($codePoint >= 0x1D482 && $codePoint <= 0x1D49B) { // 数学加粗斜体小写字母 → 普通小写字母 $normalCode = $codePoint - 0x1D421; } else { // 不在处理范围内的字符直接返回(包括特殊字符á、é等) return $char; } return mb_chr($normalCode, 'UTF-8'); }, $str); } // 测试示例1:转换URL编码的数学字体文本 $mathEncodedStr = '%F0%9D%90%B4%F0%9D%91%99%F0%9D%91%92%F0%9D%91%97%F0%9D%91%8E%F0%9D%91%9B%F0%9D%91%91%F0%9D%91%9F%F0%9D%91%8E'; echo convertMathFontToNormal($mathEncodedStr); // 输出:Alejandra // 测试示例2:保留特殊字符 $mixedStr = '𝐴𝑙é𝑗á𝑛𝑑𝑟ñç𝑎'; echo convertMathFontToNormal($mixedStr); // 输出:Aléjáñçra
为什么之前的方法无效?
mb_convert_encoding、iconv这类编码转换函数针对的是字符编码格式的转换,但数学字体和普通文本同属UTF-8编码,只是字符的Unicode码点不同,因此编码转换无法解决问题。iconv('UTF-8','ASCII//TRANSLIT',$str)会将特殊字符转换为ASCII字符(比如把á转成a),不符合保留特殊字符的需求。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

