free-spacing 和 注释
Free-Spacing正则表达式
大多数现代正则表达式都支持一种称为Free-Spacing
模式的正则表达式语法。此模式允许对正则表达式进行格式化,使人们更容易阅读。在本教程中讨论的正则表达式中,只有XML Schema以及POSIX和GNU不支持它。普通的JavaScript也不支持,但是XRegExp可以。通常通过在正则表达式外部设置选项或标志来启用该模式。我们可以使用模式修饰符的方式,将(?x)放在正则表达式的最开始,以使正则表达式的其余部分可以Free-Spacing。
在Free-Spacing模式下,正则表达式标记之间的空白将被忽略。空白包括空格,制表符和换行符。请注意,仅标记之间的空格被忽略。a b c与free-spacing模式下的abc相同。但是\ d
和\d
不相同。前者匹配d ,而后者匹配一个数字。\ d
是由反斜杠和“ d”组成的单个正则表达式令牌。用空格将标记分解会给我们一个转义的空格(与空格匹配)和一个字符“ d”。
同样,分组修饰符也无法分解。(?>atomic)
与(? ato mic )
和( ?> ato mic )
。它们都匹配相同的原子组。它们与(? >atomic)
不同。后者是语法错误。?>
在正则表达式中,表示一个组修饰符,它们是一个整体,不可以分割,并且必须保持在一起。所有此类构造(包括lookround,命名组等)都是如此。
忽略哪些空格和换行符取决于正则表达式引擎。本教程中讨论的所有样式都忽略ASCII空格,制表符,换行符,回车符和换页符。JGsoft V2和Boost是唯一忽略所有Unicode空格和换行符的。Perl始终将非ASCII空格视为文字。Perl 5.22和更高版本会忽略非ASCII换行符。Perl 5.16和以前的版本将它们视为文字。Perl 5.18和5.20将未转义的非ASCII换行符视为Free-Spacing模式中的错误,从而为开发人员提供了过渡期。
字符类中的Free-Spacing
字符类通常被视为单个标记。[abc]
和[ a b c ]
是不一样的。前者匹配三个字母之一,而后者匹配这三个字母之一或一个空格。换句话说:Free-Spacing模式在字符类中不起作用。字符类中的空格和换行符将包含在字符类中。这意味着在Free-Spacing模式下,我们可以使用\
(反斜杠后面有个空格)或[ ]
来匹配单个空格。当然,十六进制转义\ x20
也可以正常匹配。
但是,Java在Free-Spacing模式下不会将字符类视为单个标记。Java确实会忽略字符类中的空格,换行符和注释。因此,在Java的Free-Spacing模式下,[abc]
与[ a b c ]
相同。要在字符类中添加空格,我们必须使用反斜杠对其进行转义。但是,即使在Free-Spacing模式下,^
也必须紧接在左括号之后。[ ^ a b c ]
匹配四个字符^ ,a ,b或c中的任何一个,就和[abc^]
一样。将^写到正确的位置,[^ a b c ]
匹配不是a ,b或c的任何字符。
Perl 5.26在字符类中提供了有限的Free-Spacing选项。在Perl之前的版本中,/x在字符类之外使用的时候才会激活Free-Spacing模式。两个x的标记 /xx
还使Perl 5.26可以将字符类中未转义的空格和制表符视为Free-Spacing。换行符仍然是字符类中的文字。如果将标志PCRE2_EXTENDED_MORE传递给pcre2_compile()
,则PCRE2 10.30支持与Perl 5.26相同的/xx模式。
Perl 5.26和PCRE 10.30还添加了一个新的模式修饰符(?xx)
,该修饰符在字符类内部和外部都能实现Free-Spacing。(?x)
像先前介绍的一样对于外部字符类的标记启用Free-Spacing,但对字符类内部则不起作用。(?-x)
和(?-xx)
都完全关闭Free-Spacing。
在Java中将[ ^ a ]
中的^仅仅视为一个普通的字符。即使我们设定了要忽略空格,但是它们仍然会破坏Java中^的特殊含义。Perl的5.26和PCRE2 10.30在/xx
模式下将[ ^ a ]
中的^视为否定插入符。Perl 5.26和PCRE2 10.30完全忽略了Free-Spacing。它们仍然认为^位于字符类的开始。
Free-Spacing模式中的注释
Free-Spacing模式的另一个功能是使用#字符在正则表达式中增加注释。注释一直到该行的末尾。从#到下一个换行符的所有内容都将被忽略。JGsoft V2是唯一可以识别所有Unicode换行符的样式。 XPath和Oracle即使具有Free-Spacing模式,也不支持正则表达式中的注释。他们总是将#视为文字字符。
Java提供的正则引擎是唯一一个支持在Free-Spacing模式下将#视为字符类中注释开头的。注释将一直运行到该行的末尾,因此我们可以使用[]
关闭注释。所有其他正则引擎都将#视为字符类中的普通的字符。其中包括/xx
模式下的Perl 5.26 。
将所有内容放在一起,可以通过编写多行来分别注释与有效日期匹配的正则表达式:
#使用yyyy-mm-dd 格式 匹配21世纪的20th
(19|20)\d\d # year (group 1)
[- /.] # separator
(0[1-9]|1[012]) # month (group 2)
[- /.] # separator
(0[1-9]|[12][0-9]|3[01]) # day (group 3)
没有Free-Spacing模式的注释
许多正则引擎还允许我们在不使用Free-Spacing模式的情况下向正则表达式添加注释。语法为(?#comment)
,其中“ comment”可以是我们想要的任何形式,只要它不包含右括号即可。正则表达式引擎将忽略(?#
之后的第一个右括号之前的所有内容。
在本教程中讨论的各种正则引擎中,所有支持Free-Spacing模式注释的正则引擎(Java和Tcl除外)也都支持(?#comment)
。在Free-Spacing模式下不支持注释或完全不支持Free-Spacing模式的正则引擎同样也不支持(?#comment)
。