“[^] []”正则表达式是什么意思?

42

我在下面的正则表达式中找到了它:

\[(?:[^][]|(?R))*\]

它匹配方括号(及其内容)以及嵌套的方括号。

1个回答

69

[^][]是一个字符类,表示除了[]之外的所有字符。

由于PCRE不会产生歧义,因此可以避免转义[]特殊字符,PCRE是在preg_函数中使用的正则表达式引擎。

由于[^]在PCRE中是不正确的,正则表达式只能解析]在字符类内部并稍后被关闭的情况,[也是同样的道理。它不能重新打开一个字符类(除了POSIX字符类[:alnum:])内部的字符类。然后最后的]是清晰的,它是字符类的结尾。然而,字符类外部的[必须转义,因为它被解析为字符类的开始。

同样地,您可以编写[]][[][^[],而无需转义字符类中的[]

注意:自PHP 7.3以来,您可以使用内联xx修饰符,即使在字符类内部也可以忽略空白字符。这样,您可以以较少的歧义方式编写这些类,例如:(?xx)[^ ][ ] [ ] ] [ [ ] [^ [ ]

您可以在多个正则表达式环境中使用此语法:PCRE(PHP,R),Perl,Python,Java,.NET,GO,awk,Tcl(如果使用花括号分隔模式,感谢Donal Fellows)等。

但是不能使用的环境包括:Ruby,JavaScript(除了IE<9)等。

正如m.buettner所指出的,[^]]不会产生歧义,因为]第一个字符,[^a]]被视为不是a后跟]的所有内容。要有a],必须写成:[^a\]][^]a]

在JavaScript的特殊情况下,规范允许[]作为永远不匹配的正则表达式标记(换句话说,[]将始终失败),而[^]作为匹配任何字符的正则表达式。然后[^]]被视为任何字符后跟]。实际的实现方式因环境而异,但现代浏览器通常遵循规范中的定义。

模式细节:

\[          # literal [
(?:         # open a non capturing group
    [^][]   # a character that is not a ] or a [
  |         # OR
    (?R)    # the whole pattern (here is the recursion)
)*          # repeat zero or more time
\]          # a literal ]

在你的模式示例中,不需要转义最后一个 ] 符号。

但是你可以用稍微优化了一点,并且更有用,因为可以重复使用作为子模式(使用 (?-1))的模式来实现相同的功能:(\[(?:[^][]+|(?-1))*+])

(                     # open the capturing group
    \[                # a literal [
        (?:           # open a non-capturing group
            [^][]+    # all characters but ] or [ one or more time
          |           # OR
            (?-1)     # the last opened capturing group (recursion)
                      # (the capture group where you are)
        )*+           # repeat the group zero or more time (possessive)
    ]                 # literal ] (no need to escape)
)                     # close the capturing group

或者更好的方法是:(\[[^][]*(?:(?-1)[^][]*)*+]),它避免了使用选择分支所产生的代价。


29
但你应该转义那些特殊字符,因为这会让维护你的代码的人感到困惑。正则表达式的作者倾向于编写"棘手"的代码(我也有这方面的经验),但是这样的代码很难理解。 - cdhowie
3
请注意,这里的重点是 ] 出现在第一个字符位置(在否定符号之后),因为空字符类是不允许的。 - Martin Ender
11
特别是如果你也在使用 JavaScript,其中 [^] 是有效的正则表达式(表示“任何字符”)。 - Tim Pietzcker
3
除了在IE 9及以下版本中,[^]的行为类似于PHP中本答案所示的方式。 - Izkata
2
@CasimiretHippolyte,这不是关于它们是否“能够”解析正则表达式的问题,而是关于你是否已经清晰地表达了你的正则表达式的意图。大多数语言认为空格不重要,但我们通过单独放置语句来自由使用它。例如,这不是为了编译器的好处,而是为未来的维护者着想。这是另外一个这样的情况,编译器不在乎,但是下一个维护你代码的人会感谢你没有让他停下来并猜测你的意图。 - cdhowie
显示剩余15条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接