具有前瞻和后瞻的PCRE正则表达式总是返回true

时间:2014-01-08 12:20:46

标签: php regex pcre regex-lookarounds

我正在尝试为表单验证创建一个正则表达式,但它总是返回true。用户必须能够添加{user|2|S}之类的内容作为输入,但如果使用\进行转义,也可以使用括号。

此代码现在检查左括号{

$regex = '/({(?=([a-zA-Z0-9]+\|[0-9]*\|(S|D[0-9]*)}))|[^{]|(?<=\\\){)*/';
if (preg_match($regex, $value)) {
     return TRUE;
} else {
    return FALSE;
}

可能的正确输入是:

Hello {user|1|S}, you have {amount|2|D2}

Hello {user|1|S}, you have {amount|2|D2} in \{the_bracket_bank\}

但是,这应该返回false:

Hello {user|1|S}, you have {amount|2}

这也是:

Hello {user|1|S}, you have {amount|2|D2} in {the_bracket_bank}

可以在这里找到一个实例:http://regexr.com?37tpu请注意,最后在lookbehind中有一个\,PHP给了我错误消息,因为我不得不在我的额外时间中逃避它代码。

3 个答案:

答案 0 :(得分:1)

匹配而不看后面

您可以在不使用lookbehind / lookaheads(通常建议使用)的情况下为此制作正则表达式。

例如,如果您的要求是您可以匹配任何字符,只有{},除非它前面有\。你也可以说:

匹配任何字符,但{}或匹配\{\}。要匹配除{}之外的任何字符:

[^{}]

匹配\{使用:

\\\{

一个反斜杠用于转义{(这可能不是必需的,具体取决于你的正则表达式编译器),一个反斜杠用于转义另一个反斜杠。

你最终会得到这个:

(?:
    [^{}]
|
    \\\{
|
    \\\}
)+

我很好地格式化了这个正则表达式,因此它是可读的。如果你想在你的代码中使用它,请确保使用[PCRE_EXTENDED][1]修饰符。

答案 1 :(得分:1)

主要错误是您没有指定正则表达式应该从检查字符串的开头到匹配。使用^$断言。

我认为你必须在正则表达式中逃避{},因为它们具有特殊含义。它们共同构成了量词。

(?<=\\\)写得更好(?<=\\\\)。反斜杠必须双重转义,因为它在单引号字符串和PCRE正则表达式中都有特殊含义。使用\\\也可以,因为如果单引号字符串包含除\\\'之外的任何转义序列,它会将其作为文字反斜杠和字母处理,因此\)字面意思。但两次明确地避免反斜杠似乎更容易让我读到。

正则表达式应该是

$regex = '/^(\{(?=([a-zA-Z0-9]+\|[0-9]*\|(S|D[0-9]*)\}))|[^{]|(?<=\\\\)\{)*$/';

但请注意,环视断言不是必需的。这个正则表达式也应该完成这项工作:

$regex = '/^([^{]|\\\{|\{[a-zA-Z0-9]+\|[0-9]*\|(S|D[0-9]*)\})*$/';

任何非{字符都与第一个替代字符匹配。当读取{时,使用剩余的两个备选方案之一。大括号事物的模式匹配,或者正则表达式引擎回溯一个字符并尝试匹配\{字符序列。如果两种方式都失败了,它会进一步回溯直到它到达字符串并完全失败。

答案 2 :(得分:0)

对我来说看起来更像是一份工作:

/((?<!\\\\)\{[a-zA-Z0-9]+\|[0-9]+\|[SD][0-9]*\})/

然而,混淆因素是如此之高,我宁愿识别所有括号内的字符串并稍后解析它们。