【问题标题】:PCRE regex with lookahead and lookbehind always returns true具有前瞻和后视的 PCRE 正则表达式始终返回 true
【发布时间】:2014-01-08 12:20:46
【问题描述】:

我正在尝试为表单验证创建一个正则表达式,但它总是返回 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 请注意,在末尾的后面有一个 \,PHP 给了我错误消息,因为我不得不在我的代码中额外地转义它。

【问题讨论】:

  • 您可能会发现转储 pregmatch 的第三个参数(即查看匹配的内容)并单独测试每个 OR 正则表达式更容易。记录您的正则表达式也会对(您)有所帮助。
  • 为什么正则表达式不应该匹配Hello {user|1|S}, you have {amount|2|D2} in {the_bracket_bank}

标签: php regex pcre regex-lookarounds


【解决方案1】:

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

我认为您必须在正则表达式中转义 {},因为它们具有特殊含义。它们一起构成一个量词。

(?&lt;=\\\) 最好写成(?&lt;=\\\\)。反斜杠必须进行双重转义,因为它在单引号字符串和 PCRE 正则表达式中都有特殊含义。使用\\\ 也有效,因为如果单引号字符串包含除\\\' 之外的任何转义序列,它会将其作为文字反斜杠和字母处理,因此\) 按字面意思理解。但是对我来说,两次明确地转义反斜杠似乎更容易阅读。

正则表达式应该是

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

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

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

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

【讨论】:

  • 就像一个魅力。不过,如果没有环视断言,还没有尝试过
【解决方案2】:

无需后视即可匹配

您可以为此创建一个正则表达式,而无需使用lookbehind/lookaheads(通常推荐)。

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

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

[^{}]

要匹配\{,请使用:

\\\{

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

你最终会得到这个:

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

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

【讨论】:

  • 感谢您提供这个很好且解释清楚的答案。这可能也行得通,但 Palec 的解决方案立即奏效,并按应有的方式处理了所有事情
  • 是的,一个正则表达式当然是好的。我今天也不完全清楚:P。我更新了我的答案,只包括关于匹配的解释,没有环视。
【解决方案3】:

在我看来更像是一项工作:

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

但是,混淆系数太高了,我宁愿识别所有带括号的字符串并稍后解析它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-13
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    相关资源
    最近更新 更多