PHP preg_replace: 以case/diacritic-insensitive方式高亮匹配一个键的整个单词
PHP preg_replace: highlight whole words matching a key in case/diacritic-insensitive way
我需要在 UTF-8 $文本中突出显示与 $key 匹配的单个单词或短语(整个单词,而不是子字符串)。这种匹配必须既不区分大小写又不区分变音符号。突出显示的文本必须保持原样(包括 uppercase/lowercase 个字符和变音符号,如果存在)。
下面的表达式实现了一半的目标:
$text = preg_replace( "/\b($key)\b/i", '<div class="highlight"></div>', $text );
它不区分大小写并匹配整个单词,但如果匹配 $key 的 $text 部分包含 $key 中不存在的变音符号,则不会突出显示这些部分。
例如。我想在传递 $key = "bjorn kallstrom".
的 $text 中突出显示 "Björn Källström"
欢迎提出任何绝妙的想法(使用 preg_replace 或其他 PHP 函数)。
仅通过函数调用是不可能的,您必须实现它。
- 从 HTML (
$document->documentElement->textContent
) 中提取文本
- 将文本拆分为单词并对其进行规范化 - 保留原件 (
$words[$normalized][] = $original
) - 基本上这为您提供了每个规范化单词的变体列表。
- 拆分和规范化搜索查询
- 从搜索查询中编译 RegEx 模式以匹配
((word1_v1|word1_v2)\s*(word2_v1|word2_v2))u
并验证 (^(word1_v1|word1_v2)\s*(word2_v1|word2_v2)$)u
- 遍历您 HTML 文档中的文本节点
$xpath->evaluate('//text()')
- 使用
preg_split()
通过搜索字符串分隔文本,捕获定界符(搜索匹配)
- 遍历该列表,如果不是搜索字符串匹配,则将它们添加为文本节点,否则添加 HTML 结构以突出显示
- 去除原文节点
一个想法是将键转换为模式,用一个字符替换所有有问题的字符 class:
$corr = ['a' => '[aàáâãäå]', 'o' => '[oòóôõö]',/* etc. */];
$key = 'bjorn kallstrom';
$pattern = '/\b' . strtr($key, $corr) . '\b/iu';
$text = preg_replace($pattern, '<em class="highlight">[=10=]</em>', $text);
请注意,由于您正在处理 unicode 字符,因此需要使用 u 修饰符来避免意外行为,尤其是在单词边界方面。
如果您的键已经包含重音字符,请先将它们转换为 ascii:
$key = 'björn kallstrom';
$key = iconv('UTF-8', 'ASCII//TRANSLIT', $key);
(如果您获得 ?
代替字母,这意味着您的语言环境设置为 C 或 POSIX。在这种情况下,将它们更改为 en_US.UTF-8,或您系统中可用的另一个。请参阅 setlocale)
另请参阅非常有用的 intl classes:Normalizer and Transliterator.
注意:如果要突出显示多个键,请一次完成所有操作。将数组按长度排序(最长的优先使用mb_strlen
),使用array_map
将键音译为ascii,并使用|
对数组进行内爆。目标是获得模式: '/\b(?:' . implode('|', $keys) . ')\b/iu'
和 bj[oòóôõö]rn k[aàáâãäå]llstr[oòóôõö]m
在 bj[oòóôõö]rn
之前单独(例如)。
我需要在 UTF-8 $文本中突出显示与 $key 匹配的单个单词或短语(整个单词,而不是子字符串)。这种匹配必须既不区分大小写又不区分变音符号。突出显示的文本必须保持原样(包括 uppercase/lowercase 个字符和变音符号,如果存在)。
下面的表达式实现了一半的目标:
$text = preg_replace( "/\b($key)\b/i", '<div class="highlight"></div>', $text );
它不区分大小写并匹配整个单词,但如果匹配 $key 的 $text 部分包含 $key 中不存在的变音符号,则不会突出显示这些部分。 例如。我想在传递 $key = "bjorn kallstrom".
的 $text 中突出显示 "Björn Källström"欢迎提出任何绝妙的想法(使用 preg_replace 或其他 PHP 函数)。
仅通过函数调用是不可能的,您必须实现它。
- 从 HTML (
$document->documentElement->textContent
) 中提取文本
- 将文本拆分为单词并对其进行规范化 - 保留原件 (
$words[$normalized][] = $original
) - 基本上这为您提供了每个规范化单词的变体列表。 - 拆分和规范化搜索查询
- 从搜索查询中编译 RegEx 模式以匹配
((word1_v1|word1_v2)\s*(word2_v1|word2_v2))u
并验证(^(word1_v1|word1_v2)\s*(word2_v1|word2_v2)$)u
- 遍历您 HTML 文档中的文本节点
$xpath->evaluate('//text()')
- 使用
preg_split()
通过搜索字符串分隔文本,捕获定界符(搜索匹配) - 遍历该列表,如果不是搜索字符串匹配,则将它们添加为文本节点,否则添加 HTML 结构以突出显示
- 去除原文节点
一个想法是将键转换为模式,用一个字符替换所有有问题的字符 class:
$corr = ['a' => '[aàáâãäå]', 'o' => '[oòóôõö]',/* etc. */];
$key = 'bjorn kallstrom';
$pattern = '/\b' . strtr($key, $corr) . '\b/iu';
$text = preg_replace($pattern, '<em class="highlight">[=10=]</em>', $text);
请注意,由于您正在处理 unicode 字符,因此需要使用 u 修饰符来避免意外行为,尤其是在单词边界方面。
如果您的键已经包含重音字符,请先将它们转换为 ascii:
$key = 'björn kallstrom';
$key = iconv('UTF-8', 'ASCII//TRANSLIT', $key);
(如果您获得 ?
代替字母,这意味着您的语言环境设置为 C 或 POSIX。在这种情况下,将它们更改为 en_US.UTF-8,或您系统中可用的另一个。请参阅 setlocale)
另请参阅非常有用的 intl classes:Normalizer and Transliterator.
注意:如果要突出显示多个键,请一次完成所有操作。将数组按长度排序(最长的优先使用mb_strlen
),使用array_map
将键音译为ascii,并使用|
对数组进行内爆。目标是获得模式: '/\b(?:' . implode('|', $keys) . ')\b/iu'
和 bj[oòóôõö]rn k[aàáâãäå]llstr[oòóôõö]m
在 bj[oòóôõö]rn
之前单独(例如)。