Kam*_*are 9 php regex unicode collation diacritics
我正在努力搜索文本中的特定单词并突出显示它们.代码工作得很好,除了我希望它也匹配相似的字母.我的意思是,搜索fête应该匹配fêté,fete,...
这样做有简单而优雅的方法吗?
这是我目前的代码:
$regex='/(' . preg_replace('/\s+/', '|', preg_quote($usersearchstring)) .')/iu';
$higlightedtext = preg_replace($regex, '<span class="marked-search-text">\0</span>', $text);
Run Code Online (Sandbox Code Playgroud)
我的文字不是html编码的.在MariaDB中搜索匹配相似的结果.
[编辑]这里有一个较长的问题示例:
$usersearchstring='fête';
$text='la paix fêtée avec plus de 40 cultures';
$regex='/(' . preg_replace('/\s+/', '|', preg_quote($usersearchstring)) .')/iu';
$higlightedtext = preg_replace($regex, '<span class="marked-search-text">\0</span>', $text);
Run Code Online (Sandbox Code Playgroud)
结果是$ higlightedtext与$ text相同
当改变$ higlightedtext时,单词"fêté"然后是$ higlightedtext
'la paix <span class="marked-search-text">fêté</span>e avec plus de 40 cultures'
Run Code Online (Sandbox Code Playgroud)
但是,我希望它能够"始终"匹配字母的所有变体,因为可能存在(并且实际上)可能的单词的许多变体.我们有fêtefêté甚至可能在数据库中的盛宴.
我一直在考虑这个,但我看到的唯一解决方案是拥有一个包含所有字母替换选项的巨大数组,然后循环遍历它们并尝试每个变体.但这并不优雅而且会很慢.(因为对于很多字母我至少有5种变体:aáàâä,导致,如果这个单词有3个元音,我需要做75x(5x5x5)preg_replace.
[/编辑]
您的问题是关于整理的,即使用有关语言词汇规则的知识来处理自然语言文本以对其进行排序和比较的艺术。您正在寻找不区分大小写和不区分变音标记的排序规则。
一个常见的整理规则是B
在 之后A
。一个不太常见的规则,但重要的是你的问题,是ê
和e
是等价的。 排序规则包含许多这样的规则,经过多年精心制定。如果您使用不区分大小写的排序规则,您需要类似和等价的规则。a
A
在大多数欧洲语言(但不是西班牙语)中存在的变音规则是:Ñ
和N
是等价的。在西班牙语中,Ñ
在N
.
现代数据库知道这些排序规则。例如,如果您使用 MySQL,您可以设置一个字符编码为utf8mb4
、排序规则为 的列utf8mb4_unicode_ci
。这对大多数语言都很好(但不适合西班牙语)。
正则表达式技术对于整理工作不是很有用。如果您为此使用正则表达式,则您正在尝试重新发明轮子,而您可能会重新发明爆胎。
PHP 与大多数现代编程语言一样,包含内置在其Collator 类中的整理支持。下面是一个将 Collator 对象用于重音字符用例的简单示例。它使用Collator::PRIMARY 整理强度来执行不区分大小写和重音的比较。
mb_internal_encoding("UTF-8");
$collator = collator_create('fr_FR');
$collator->setStrength(Collator::PRIMARY);
$str1 = mb_convert_encoding('fêté', 'UTF-8');
$str2 = mb_convert_encoding('fete', 'UTF-8');
$result = $collator->compare($str1, $str2);
echo $result;
Run Code Online (Sandbox Code Playgroud)
在$result
这里是零,这意味着字符串相等。那就是你想要的。
如果要以这种方式搜索字符串中的匹配子字符串,则需要使用显式子字符串匹配来进行。正则表达式技术不提供这一点。
这是一个执行搜索和注释的函数(<span>
例如,添加标签)。它充分利用了 Collator 类的字符相等方案。
function annotate_ci ($haystack, $needle, $prefix, $suffix, $locale="FR-fr") {
$restoreEncoding = mb_internal_encoding();
mb_internal_encoding("UTF-8");
$len = mb_strlen($needle);
if ( mb_strlen( $haystack ) < $len ) {
mb_internal_encoding($restoreEncoding);
return $haystack;
}
$collator = collator_create( $locale );
$collator->setStrength( Collator::PRIMARY );
$result = "";
$remain = $haystack;
while ( mb_strlen( $remain ) >= $len ) {
$matchStr = mb_substr($remain, 0, $len);
$match = $collator->compare( $needle, $matchStr );
if ( $match == 0 ) {
/* add the matched $needle string to the result, with annotations.
* take the matched string from $remain
*/
$result .= $prefix . $matchStr . $suffix;
$remain = mb_substr( $remain, $len );
} else {
/* add one char to $result, take one from $remain */
$result .= mb_substr( $remain, 0, 1 );
$remain = mb_substr( $remain, 1 );
}
}
$result .= $remain;
mb_internal_encoding($restoreEncoding);
return $result;
}
Run Code Online (Sandbox Code Playgroud)
这是使用该功能的示例。
$needle = 'Fete'; /* no diacriticals here! mixed case! */
$haystack= mb_convert_encoding('la paix fêtée avec plus de 40 cultures', 'UTF-8');
$result = annotate_ci($haystack, $needle,
'<span class="marked-search-text">' , '</span>');
Run Code Online (Sandbox Code Playgroud)
它回馈
la paix <span class="marked-search-text">fêté</span>e avec plus de 40 cultures
Run Code Online (Sandbox Code Playgroud)