9

是否有正则表达式来匹配带有和不带有特殊字符的特定字符串?可以这么说,特殊字符不敏感。

Likecéra将匹配cera,反之亦然。

有任何想法吗?

编辑:我想匹配带有和不带有特殊/重音字符的特定字符串。不仅仅是任何字符串/字符。

测试示例:

$clientName   = 'céra';
$this->search = 'cera';

$compareClientName = strtolower(iconv('utf-8', 'ascii//TRANSLIT', $clientName));
$this->search      = strtolower($this->search);

if (strpos($compareClientName, $this->search) !== false)
{
    $clientName = preg_replace('/(.*?)('.$this->search.')(.*?)/iu', '$1<span class="highlight">$2</span>$3', $clientName);
}

输出:<span class="highlight">céra</span>

如您所见,我想突出显示特定的搜索字符串。但是,我仍然想显示匹配字符串的原始(重音)字符。

我想我必须以某种方式将其与Michael Sivolobov 的答案结合起来。

我想我必须使用单独的preg_match()and preg_replace(),对吗?

4

4 回答 4

9

您可以使用该\p{L}模式匹配任何字母。

资源

您必须u在正则表达式之后使用修饰符才能启用 unicode 模式。

例子 :/\p{L}+/u

编辑 :

尝试这样的事情。它应该用重音替换每个字母到包含重音字母(单字符和 unicode 双字符)和非重音字母的搜索模式。然后,您可以使用更正后的搜索模式突出显示您的文本。

function mbStringToArray($string)
{
    $strlen = mb_strlen($string);
    while($strlen)
    {
        $array[] = mb_substr($string, 0, 1, "UTF-8");
        $string = mb_substr($string, 1, $strlen, "UTF-8");
        $strlen = mb_strlen($string);
    }
    return $array;
}

// I had to use this ugly function to remove accents as iconv didn't work properly on my test server.
function stripAccents($stripAccents){
    return utf8_encode(strtr(utf8_decode($stripAccents),utf8_decode('àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ'),'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY'));
}

$clientName = 'céra';

$clientNameNoAccent = stripAccents($clientName);

$clientNameArray = mbStringToArray($clientName);

foreach($clientNameArray as $pos => &$char)
{
    $charNA =$clientNameNoAccent[$pos];
    if($char != $charNA)
    {
        $char = "(?:$char|$charNA|$charNA\p{M})";
    }
}

$clientSearchPattern = implode($clientNameArray); // c(?:é|e|e\p{M})ra

$text = 'the client name is Céra but it could be Cera or céra too.';

$search = preg_replace('/(.*?)(' . $clientSearchPattern . ')(.*?)/iu', '$1<span class="highlight">$2</span>$3', $text);

echo $search; // the client name is <span class="highlight">Céra</span> but it could be <span class="highlight">Cera</span> or <span class="highlight">céra</span> too.
于 2013-09-26T08:33:58.380 回答
7

如果您想知道某个字母上是否有重音或其他标记,您可以通过匹配模式来检查它\p{M}

更新

您需要将模式中的所有重音字母转换为一组备选方案:

例如céra -> c(?:é|e|e\p{M})ra

为什么我加了e\p{M}?因为您的字母 é 可以是 Unicode 中的一个字符,并且可以是两个字符的组合(e 和重音符号)。e\p{M}匹配带有重音符号的 e(两个单独的 Unicode 字符)

当您转换模式以匹配所有字符时,您可以在您的preg_match

于 2013-09-26T08:42:24.057 回答
3

正如您在其中一条评论中标记的那样,您不需要正则表达式,因为目标是找到特定的字符串。你为什么不使用explode?像那样:

$clientName   = 'céra';
$this->search = 'cera';

$compareClientName = strtolower(iconv('utf-8', 'ascii//TRANSLIT', $clientName));
$this->search      = strtolower($this->search);

$pieces = explode($compareClientName, $this->search);

if (count($pieces) > 1)
{
    $clientName = implode('<span class="highlight">'.$clientName.'</span>', $pieces);
}

编辑:

如果您的$search变量也可能包含特殊字符,为什么不translit使用它并使用mb_strposwith $offset?像这样:

$offset = 0;
$highlighted = '';
$len = mb_strlen($compareClientName, 'UTF-8');
while(($pos = mb_strpos($this->search, $compareClientName, $offset, 'UTF-8')) !== -1) {
    $highlighted .= mb_substr($this->search, $offset, $pos-$offset, 'UTF-8').
         '<span class="highlight">'.
         mb_substr($this->search, $pos, $len, 'UTF-8').'</span>';
    $offset = $pos + $len;
}
$highlighted .= mb_substr($this->search, $offset, 'UTF-8');

更新 2:

重要的是使用mb_函数 with 而不是 simple strlenetc。这是因为重音字符使用两个或更多字节存储;还要始终确保使用正确的编码,例如:

echo strlen('é');
> 2

echo mb_strlen('é');
> 2

echo mb_internal_encoding();
> ISO-8859-1

echo mb_strlen('é', 'UTF-8');
> 1

mb_internal_encoding('UTF-8');
echo mb_strlen('é');
> 1
于 2013-09-26T10:25:21.377 回答
2

正如您在此处看到的,POSIX equivalence class用于匹配具有相同整理顺序的字符,可以通过以下正则表达式完成:

[=a=]

这将匹配á并且取决于您的语言环境äa

于 2013-09-26T10:14:24.330 回答