【问题标题】:PHP preg_replace: highlight whole words matching a key in case/diacritic-insensitive wayPHP preg_replace:以不区分大小写/变音符号的方式突出显示与键匹配的整个单词
【发布时间】:2018-08-20 13:29:36
【问题描述】:

我需要在 UTF-8 $text 中突出显示与 $key 匹配的单个单词或短语(整个单词,而不是子字符串)。这种匹配必须既不区分大小写又不区分变音符号。突出显示的文本必须保持原样(包括大写/小写字符和变音符号,如果存在)。

以下表达式实现了一半的目标:

$text = preg_replace( "/\b($key)\b/i", '<div class="highlight">$1</div>', $text );

它不区分大小写并匹配整个单词,但不会突出显示与 $key 匹配的 $text 部分,如果这些部分包含 $key 中不存在的变音符号。 例如。我想通过 $key = "bjorn kallstrom" 在 $text 中突出显示“Björn Källström”。

欢迎任何绝妙的想法(使用 preg_replace 或其他 PHP 函数)。

【问题讨论】:

  • 带有类的字体标签,有点蒸汽朋克。
  • @Casimir et Hippolyte:好的,我用“div”替换了“font”标签;-)
  • @Jason Grim:不,我不认为这是重复的:您链接的问题根本不考虑变音符号。

标签: php regex preg-replace


【解决方案1】:

一个想法是将键转换为模式,用字符类替换所有有问题的字符:

$corr = ['a' => '[aàáâãäå]', 'o' => '[oòóôõö]',/* etc. */];

$key = 'bjorn kallstrom';

$pattern = '/\b' . strtr($key, $corr) . '\b/iu';

$text = preg_replace($pattern, '<em class="highlight">$0</em>', $text);

请注意,由于您处理的是 unicode 字符,因此您需要使用 u 修饰符来避免意外行为,尤其是单词边界。

如果您的键已经包含重音字符,请先将它们转换为 ascii:

$key = 'björn kallstrom';
$key = iconv('UTF-8', 'ASCII//TRANSLIT', $key);

(如果您获得? 代替字母,这意味着您的语言环境设置为 C 或 POSIX。在这种情况下,将它们更改为 en_US.UTF-8 或系统中可用的另一个。见setlocale)

还可以看看非常有用的 intl 类:NormalizerTransliterator

注意:如果您有多个要突出显示的键,请一口气完成所有操作。按长度对数组进行排序(最长的第一个使用mb_strlen),使用array_map 将键音译为ascii,并使用| 对数组进行内爆。目标是获得模式:'/\b(?:' . implode('|', $keys) . ')\b/iu'bj[oòóôõö]rn k[aàáâãäå]llstr[oòóôõö]mbj[oòóôõö]rn 之前(例如)。

【讨论】:

    【解决方案2】:

    仅通过函数调用是不可能的,您必须实现它。

    1. 从 HTML 中提取文本 ($document-&gt;documentElement-&gt;textContent)
    2. 将文本拆分为单词并对其进行规范化 - 保留原件 ($words[$normalized][] = $original) - 基本上这会为您提供每个规范化单词的变体列表。
    3. 拆分和规范化搜索查询
    4. 从搜索查询中编译 RegEx 模式以匹配 ((word1_v1|word1_v2)\s*(word2_v1|word2_v2))u 并验证 (^(word1_v1|word1_v2)\s*(word2_v1|word2_v2)$)u
    5. 遍历 HTML 文档中的文本节点 $xpath-&gt;evaluate('//text()')
    6. 使用preg_split()通过搜索字符串分隔文本,捕获分隔符(搜索匹配)
    7. 如果不是搜索字符串匹配,则遍历该列表并将它们添加为文本节点,否则添加 HTML 结构以突出显示
    8. 删除原始文本节点。

    【讨论】:

      猜你喜欢
      • 2013-10-19
      • 2023-03-06
      • 2013-04-01
      • 2011-02-14
      • 1970-01-01
      • 2013-08-16
      • 2019-01-18
      • 2014-10-26
      • 1970-01-01
      相关资源
      最近更新 更多