Php 匹配文字字符串
我有这个网页,用户可以在其中添加笑脸到他们的评论。我想限制每条评论中笑脸的数量。“系统”工作正常,但我对regex部分有一些问题。 我在配置文件中定义了我的微笑,如下所示:Php 匹配文字字符串,php,regex,Php,Regex,我有这个网页,用户可以在其中添加笑脸到他们的评论。我想限制每条评论中笑脸的数量。“系统”工作正常,但我对regex部分有一些问题。 我在配置文件中定义了我的微笑,如下所示: $config['Smilies'] = Array ( // irrelevant stuff 'smilies' => Array ( ':)' => 'smile.gif', ':(' => 'sad.gif', // some more
$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”。我对正则表达式的了解非常贫乏,我无法理解这一点。正则表达式是默认的(至少是PCREs)。通常你可以绕过这一点:
/a+/ # selects the whiole string from "aaaaaaa"
/a+?/ # selects only "a"
对你来说,这没有多大帮助,因为你不能在某个地方打个问号。唯一的可能是重新排序您的搜索数组,并立即替换找到的位置。首先搜索以查找s:10
,然后搜索以查找s:1
,并使用而不是匹配项。这样,第二个就再也找不到第一个了
另一种可能性:将搜索数组一分为二。如果您知道,这个循环的结构总是:'加上数字,那么您可以在第二个循环中使用regexp,如下所示
Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '(?![0-9])/i', $Content, $matches );
使用(?![0-9])
a查找任何非数字
和第三个:如果您只允许(=转换)特定位置的微笑,您可以使用:
Preg_Match_All ( '/\b' . Preg_Quote ( $smilie ) . '\b/i', $Content, $matches );
\b
是一个“单词边界”,通常不是(字母、数字、下划线)。缺点很明显,并不是所有的笑脸(如“abc;-)xyz”)都会被找到。您的代码计算每个笑脸代码在帖子中出现的次数,因此“s: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);
您可以将正则表达式更改为使用或\s(空格)匹配,使
s:1
变为\bs:1\b
或\ss:1\s
。注意,第二种方法s:1.
将不匹配,而且两个版本都不匹配这是我的有趣文本:1
将“s:1”更改为“s:1[^0-9]”—它匹配任何“s:1”,但后面不跟另一个数字。我想象这段代码比正则表达式快
$replaced = str_replace(array_keys($config['Smilies']),
array_values($config['Smilies']),
$message, $count);
但是,这并不能解决s:1
和s:10
的问题,因此我建议对此使用更清晰的分隔符/边界符号,例如:s10:
而不是s:10
。那就不再是问题了
此外,我建议无论如何不要使用数字标识符。用户可能会发现记住它们很乏味。为什么不使用易于记忆的标签,例如,
:heart:
或:lol:
?也许你应该将s:1改为s:01等。我认为这不管用,因为他开始对每个笑脸进行新的正则表达式搜索。就像Fortega说的,这对我不管用。如果我一找到微笑就替换它,这是可能的,但我必须先验证,然后如果验证通过,将文本微笑转换为图像……但是如果替换已经由第一个正则表达式完成,那么第二个正则表达式将找不到s:1+1我使用了您的第二种解决方案(第三种方案不可接受)。我不必将阵列一分为二。工作起来很有魅力!谢谢这同样有效,但我选择了Boldewyn的解决方案,因为它需要更少的代码更改。谢谢你,安威!是的,著名的或表达式+1,我忘记了这个简单的例子。我在一些笑脸上有人类可读的标签,但我无法为30个笑脸找到标签……但是,当它出现在字符串的最后时,它与“s:1”不匹配。正则表达式后面需要另一个字符。在这种情况下,负前瞻会更好:s:1(?![0-9])
。