You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高亮文本(用<span>标签包裹)时保留重音字符的方法

解决PHP高亮带重音文本时保留重音的问题

你的代码里重音丢失的核心原因是:

  • 使用iconv('utf-8', 'ISO-8859-1//IGNORE')转换编码时,很多UTF-8重音字符在ISO-8859-1中没有对应,直接被忽略了
  • Normalizer::FORM_D会把重音字符分解成基础字符+单独的重音标记,后续替换时没有还原这些标记

要实现匹配带重音的内容但保留原始重音字符,正确的做法是:不修改原始文本的编码和结构,只在匹配逻辑中做无重音的等价匹配,替换时用原始文本的内容。

修正后的代码示例

echo highlightTerm("Would you like a café, Mister Kàpêk?", "kape caf");

function highlightTerm($text, $keyword) {
    // 创建转写器:将所有字符转为拉丁字母,再去除重音
    $transliterator = Transliterator::create('Any-Latin; Latin-ASCII; [\u0300-\u036f] Remove');
    
    // 处理关键词,得到无重音的基准版本
    $normalizedKeyword = $transliterator->transliterate($keyword);
    $words = explode(" ", $normalizedKeyword);
    
    // 为每个关键词生成能匹配其重音变体的正则片段
    $patternSegments = [];
    foreach ($words as $word) {
        $charPattern = '';
        foreach (str_split($word) as $char) {
            // 匹配基础字符 + 任意重音标记的组合
            $charPattern .= "(?:" . preg_quote($char, '/') . "|[\p{M}]+" . preg_quote($char, '/') . "|" . preg_quote($char, '/') . "[\p{M}]+)";
        }
        $patternSegments[] = $charPattern;
    }
    
    $fullPattern = implode('|', $patternSegments);
    
    // 使用回调替换,确保插入的是原始文本中的带重音字符
    return preg_replace_callback(
        "/\b($fullPattern)\b/ui", // 单词边界避免部分匹配(可根据需求移除)
        function($matches) {
            return '<span style="background:yellow;">' . $matches[1] . '</span>';
        },
        $text
    );
}

代码说明

  1. 转写器处理:借助Transliterator将关键词转为无重音的形式,作为匹配的基准,同时原始文本保持不变。
  2. 正则匹配逻辑:为每个关键词的字符生成能匹配其所有重音变体的模式,确保caf能匹配café,kape能匹配Kàpêk中的对应部分。
  3. 回调替换:preg_replace_callback直接使用匹配到的原始文本片段进行高亮,完全保留重音字符。

更简化的替代方案

如果不需要太复杂的重音匹配逻辑,也可以利用preg_replace的u修饰符结合字符等价类:

echo highlightTerm("Would you like a café, Mister Kàpêk?", "kape caf");

function highlightTerm($text, $keyword) {
    // 生成无重音的关键词正则
    $normalizedKeyword = preg_replace('/[\p{M}]/u', '', Normalizer::normalize($keyword, Normalizer::FORM_KD));
    $words = array_map('preg_quote', explode(" ", $normalizedKeyword));
    $pattern = implode('|', $words);
    
    // 匹配时忽略重音,替换用原始文本
    return preg_replace_callback(
        "/(\b(?:$pattern)\b)/ui",
        function($matches) {
            return '<span style="background:yellow;">' . $matches[1] . '</span>';
        },
        $text
    );
}

内容的提问来源于stack exchange,提问作者user934820

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 10:25:23