PHP5中匹配含Nekudot的同义希伯来语单词方案咨询
希伯来语Nekudot变音符号顺序问题的PHP解决方案(PHP6之前版本适用)
一、希伯来语Nekudot的规范排序规则
根据Unicode希伯来语编码标准,同一个辅音上的变音符号(Nekudot)有明确的规范顺序:所有附加标记需要按Unicode码点从小到大排列。
拿你给出的例子来说,d6bc对应U+05BC(Dagesh,辅音上的点),d6b7对应U+05B7(Patach,元音符号),因为05BC的码点小于05B7,所以规范顺序是d6bc d6b7,也就是第一个版本的字节序列是符合标准的。
二、PHP6之前的可用解决方案(无grapheme扩展)
1. 用mbstring扩展的规范化功能(优先推荐)
如果你的服务器开启了mbstring扩展,且PHP版本在5.4及以上(PHP6之前的主流版本),直接用mb_normalize_string把字符串转成NFC规范形式就能解决问题:
$str1 = 'הִפַּלְנוּ'; $str2 = 'הִפַּלְנוּ'; // 转换为规范组合形式,统一变音符号顺序 $normStr1 = mb_normalize_string($str1, 'NFC'); $normStr2 = mb_normalize_string($str2, 'NFC'); if ($normStr1 === $normStr2) { echo "字符串匹配"; }
NFC形式会自动把同一基字符的组合标记按规范顺序排列,直接就能让两个语义相同的字符串逐位匹配。
2. 自定义函数手动排序变音符号
如果mbstring也用不了,就自己写个函数处理:遍历字符串,把每个辅音后面的变音符号单独拎出来按码点排序,再重新拼回去。代码示例:
function normalizeHebrewNekudot($str) { $result = ''; $currentBase = ''; $marks = []; $strLen = mb_strlen($str, 'UTF-8'); for ($i = 0; $i < $strLen; $i++) { $char = mb_substr($str, $i, 1, 'UTF-8'); $code = mb_ord($char, 'UTF-8'); // 判断是否是希伯来语变音符号(U+05B0到U+05BF范围) if ($code >= 0x05B0 && $code <= 0x05BF) { $marks[] = $char; } else { // 遇到新的辅音,先处理之前的辅音和标记 if ($currentBase !== '') { // 按Unicode码点升序排序标记 usort($marks, function($a, $b) { return mb_ord($a, 'UTF-8') - mb_ord($b, 'UTF-8'); }); $result .= $currentBase . implode('', $marks); $marks = []; } $currentBase = $char; } } // 处理最后一组辅音和标记 if ($currentBase !== '') { usort($marks, function($a, $b) { return mb_ord($a, 'UTF-8') - mb_ord($b, 'UTF-8'); }); $result .= $currentBase . implode('', $marks); } return $result; } // 使用示例 $str1 = 'הִפַּלְנוּ'; $str2 = 'הִפַּלְנוּ'; $norm1 = normalizeHebrewNekudot($str1); $norm2 = normalizeHebrewNekudot($str2); var_dump($norm1 === $norm2); // 输出 bool(true)
这个函数的逻辑很简单:把每个辅音和它后面的变音符号拆分,变音符号按码点排序后再和辅音拼接,这样就能统一顺序。
3. 尝试iconv扩展的转换(备选方案)
如果服务器有iconv扩展,也可以试试用它做编码转换来间接规范化:
$normStr = iconv('UTF-8', 'UTF-8//IGNORE//TRANSLIT', $originalStr);
不过这个方法的稳定性取决于服务器的iconv实现,效果可能不如前两种,只能作为备选。
内容的提问来源于stack exchange,提问作者xerostomus
相关产品推荐
相关产品推荐

