匹配文字字符串

时间:2009-12-22 09:12:27

标签: php regex

我有这个网页,用户可以在其中添加表情符号。我想限制每条评论的表情符号数量。 “系统”有效,但我对正则表达式部分有一些问题。 我在配置文件中定义了我的表情符号,如下所示:

$config['Smilies'] = Array (
    // irrelevant stuff
    'smilies' => Array (
        ':)' => 'smile.gif',
        ':(' => 'sad.gif',
        // some more smilies
        's:10' => 'worship.gif',
        's:11' => 'zip.gif',
        's:12' => 'heart.gif',
        // some more smilies
        's:1' => 'dry.gif',
        's:2' => 'lol.gif',
        's:3' => 'lollol.gif',
        // some more smilies
    )
);

然后当我验证评论时(看看有多少表情符号),我循环通过这个数组并将微笑与评论的内容相匹配。正则表达式使用如下:

foreach ( $this->config['smilies'] as $smilie => $smilieImage )
{
    $matches = Array ();
    Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '/i', $Content, $matches );

    $numOfFoundSmilies += Count ( $matches[0] );
}

问题是如果我在评论中输入“s:10”,上面的代码会找到两个匹配:“s:10”和“s:1”。我对正则表达式的了解非常差,我无法弄明白这一点。

5 个答案:

答案 0 :(得分:4)

对于每个微笑代码,您的代码会计算代码在帖子中显示的次数,因此:10'计为's:10'和's:1'。

解决方案是一次性查找所有微笑代码,以便帖子的每一部分仅计入一个微笑代码。这可以通过将所有代码组合到单个正则表达式中来完成。

$codes = array_keys($smilie);
$escCodes = array_map('preg_quote', $codes);
$regex = '/'.implode('|',$escCodes).'/i';

preg_match_all($regex, $Content, $matches);

$found = count($matches);

答案 1 :(得分:3)

默认情况下,正则表达式为greedy(至少是PCRE)。通常你可以绕过这个:

/a+/ # selects the whiole string from "aaaaaaa"

/a+?/ # selects only "a"

在你的情况下,这没有多大帮助,因为你不能只是在某个地方扔一个问号。唯一的可能是重新排序您的搜索数组,并立即替换找到的地点。搜索s:10优先s:1,并使用preg_replace()代替匹配。这样,第二个就不再找到第一个了。

另一种可能性:将您的搜索数组分成两部分。如果你知道,那个总是有结构的''加数字,你可以在第二个循环中使用你的正则表达式

Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '(?![0-9])/i', $Content, $matches );

(?![0-9])一个look ahead expression正在寻找 -digit。

还有第三个:如果您仅在某些地方允许(==转换)表情符号,则可以使用此功能:

Preg_Match_All ( '/\b' . Preg_Quote ( $smilie ) . '\b/i', $Content, $matches );

\b是一个“单词边界”,通常不是 - (字母,数字,下划线)。显然,缺点是,并非所有的表情符号(如“abc ;-) xyz”都会被找到。

答案 2 :(得分:1)

我想这个代码比正则表达式更快

$replaced = str_replace(array_keys($config['Smilies']), 
                        array_values($config['Smilies']),
                        $message, $count);

这不会解决s:1s:10的问题,所以我建议为此使用更明确的分隔符/边界表示法,例如: :s10:代替s:10。那就不再是问题了。

另外,我建议不要使用数字标识符。用户可能会发现记住它们很乏味。为什么不使用易于记忆的标签,例如:heart::lol:

答案 3 :(得分:0)

您可以将正则表达式更改为使用word boundaries或\ s(空白)进行匹配,因此s:1变为\bs:1\b\ss:1\s。请注意,第二种方法s:1.将不会匹配,并且两个版本都不匹配This is my funny texts:1

答案 4 :(得分:0)

将“s:1”更改为“s:1 [^ 0-9]” - 匹配任何“s:1”后面没有其他数字。