正则表达式详解
介绍
下面说明 PCRE 所支持的正则表达式的语法和语义。Perl 文档和很多其它书中也解说了正则表达式,有的书中有很多例子。Jeffrey Friedl 写的“Mastering Regular Expressions”,由 O'Reilly 出版社发行(ISBN 1-56592-257-3),包含了大量细节。这里的说明只是个参考文档。 正则表达式是从左向右去匹配目标字符串的一组模式。大多数字符在模式中表示它们自身并匹配目标中相应的字符。作为一个小例子,模式 The quick brown fox 匹配了目标字符串中与其完全相同的一部分。 元字符
正则表达式的威力在于其能够在模式中包含选择和循环。它们通过使用元字符来编码在模式中,元字符不代表其自身,它们用一些特殊的方式来解析。 有两组不同的元字符:一种是模式中除了方括号内都能被识别的,还有一种是在方括号内被识别的。方括号之外的元字符有这些: 
有数种用途的通用转义符 ^
断言目标的开头(或在多行模式下行的开头,即紧随一换行符之后) $
断言目标的结尾(或在多行模式下行的结尾,即紧随一换行符之前) .
匹配除了换行符外的任意一个字符(默认情况下) [
字符类定义开始 ]
字符类定义结束 |
开始一个多选一的分支 (
子模式开始 )
子模式结束 ?
扩展 ( 的含义,也是 0 或 1 数量限定符,以及数量限定符最小值 *
匹配 0 个或多个的数量限定符 +
匹配 1 个或多个的数量限定符 {
最少/最多数量限定开始 }
最少/最多数量限定结束 模式中方括号内的部分称为“字符类”。字符类中可用的元字符为: 通用转义字符 ^
排除字符类,但仅当其为第一个字符时有效 -
指出字符范围 ]
结束字符类 以下说明了每一个元字符的用法。 反斜线(\)
反斜线字符有几种用途。首先,如果其后跟着一个非字母数字字符,则取消该字符可能具有的任何特殊含义。此种将反斜线用作转义字符的用法适用于无论是字符类之中还是之外。 例如,如果想匹配一个“*”字符,则在模式中用“\*”。这适用于无论下一个字符是否会被当作元字符来解释,因此在非字母数字字符之前加上一个“\”来指明该字符就代表其本身总是安全的。尤其是,如果要匹配一个反斜线,用“\\”。 如果模式编译时加上了 PCRE_EXTENDED 选项,模式中的空白字符(字符类中以外的)以及字符类之外的“#”到换行符之间的字符都被忽略。可以用转义的反斜线将空白字符或者“#”字符包括到模式中去。 反斜线的第二种用途提供了一种在模式中以可见方式去编码不可打印字符的方法。并没有不可打印字符出现的限制,除了代表模式结束的二进制零以外。但用文本编辑器来准备模式的时候,通常用以下的转义序列来表示那些二进制字符更容易一些: \a
alarm,即 BEL 字符(0x07) \cx
"control-x",其中 x 是任意字符 \e
escape(0x1B) \f
换页符 formfeed(0x0C) \n
换行符 newline(0x0A) \r
回车符 carriage return(0x0D) \t
制表符 tab(0x09) \xhh
十六进制代码为 hh 的字符 \ddd
八进制代码为 ddd 的字符,或 backreference 
“\cx”的精确效果如下:如果“x”是小写字母,则被转换为大写字母。接着字符中的第 6 位(0x40)被反转。从而“\cz”成为 0x1A,但“\c{”成为 0x3B,而“\c;”成为 0x7B。 在“\x”之后最多再读取两个十六进制数字(其中的字母可以是大写或小写)。 在“\0”之后最多再读取两个八进制数字。以上两种情况下,如果少于两个数字,则只使用已出现的。因此序列“\0\x\07”代表两个二进制的零加一个 BEL 字符。如果是八进制数字则确保在开始的零后面再提供两个数字。 处理反斜线后面跟着一个不是 0 的数字比较复杂。在字符类之外,PCRE 以十进制数字读取该数字及其后面的数字。如果数字小于 10,或者之前表达式中捕获到至少该数字的左圆括号,则这个序列将被作为逆向引用。有关此如何运作的说明在后面,以及括号内的子模式。 在字符类之中,或者如果十进制数字大于 9 并且之前没有那么多捕获的子模式,PCRE 重新从反斜线开始读取其后的最多三个八进制数字,并以最低位的 8 个比特产生出一个单一字节。任何其后的数字都代表自身。例如: \040
另一种表示空格的方法 \40
同上,如果之前捕获的子模式少于 40 个的话 \7
总是一个逆向引用 \11
可能是个逆向引用,或者是制表符 tab \011
总是表示制表符 tab \0113
表示制表符 tab 后面跟着一个字符“3” \113
表示八进制代码为 113 的字符(因为不能超过 99 个逆向引用) \377
表示一个所有的比特都是 1 的字节 \81
要么是一个逆向引用,要么是一个二进制的零后面跟着两个字符“8”和“1” 
注意八进制值 100 或更大的值之前不能以零打头,因为不会读取(反斜线后)超过三个八进制数字。 所有的定义了一个单一字节的序列可以用于字符类之中或之外。此外,在字符类之中,序列“\b”被解释为反斜线字符(0x08),而在字符类之外有不同含义(见下面)。 反斜线的第三个用法是指定通用字符类型: \d
任一十进制数字 \D
任一非十进制数的字符 \s
任一空白字符 \S
任一非空白字符 \w
任一“字”的字符 \W
任一“非字”的字符 
任何一个转义序列将完整的字符组合分割成两个分离的部分。任一给定的字符匹配一个且仅一个转义序列。 “字”的字符是指任何一个字母或数字或下划线,也就是说,任何可以是 Perl "word" 的字符。字母和数字的定义由 PCRE 字符表控制,可能会根据指定区域的匹配而改变(见上面的“区域支持”)。举例说,在 "fr" (French) 区域,某些编码大于 128 的字符用来表示重音字母,这些字符能够被 \w 所匹配。 这些字符类型序列可以出现在字符类之中和之外。每一个匹配相应类型中的一个字符。如果当前匹配点在目标字符串的结尾,以上所有匹配都失败,因为没有字符可供匹配。 反斜线的第四个用法是某些简单的断言。断言是指在一个匹配中的特定位置必须达到的条件,并不会消耗目标字符串中的任何字符。子模式中更复杂的断言的用法在下面描述。反斜线的断言有: \b
字分界线 \B
非字分界线 \A
目标的开头(与多行模式无关) \Z
目标的结尾或位于结尾的换行符前(与多行模式无关) \z
目标的结尾(与多行模式无关) 
这些断言可能不能出现在字符类中(但是注意 "\b" 有不同的含义,在字符类之中也就是反斜线字符)。 字边界是目标字符串中的一个位置,其当前字符和前一个字符不能同时匹配 \w 或者 \W(也就是其中一个匹配 \w 而另一个匹配 \W),或者是字符串的开头或结尾,假如第一个或最后一个字符匹配 \w 的话。 \A,\Z 和 \z 断言与传统的音调符和美元符(下面说明)的不同之处在于它们仅匹配目标字符串的绝对开头和结尾而不管设定了任何选项。它们不受 PCRE_NOTBOL 或 PCRE_NOTEOL 选项的影响。\Z 和 \z 的不同之处在于 \Z 匹配了作为字符串最后一个字符的换行符之前以及字符串的结尾,而 \z 仅匹配字符串的结尾。 

解决方案 »

  1.   

    音调符(^)和美元符($)
    在字符类之外,默认匹配模式下,音调符是一个仅在当前匹配点是目标字符串的开头时才为真的断言。在字符类之中,音调符的含义完全不同(见下面)。 如果涉及到几选一时音调符不需要是模式的第一个字符,但如果出现在某个分支中则应该是该选择分支的第一个字符。如果所有的选择分支都以音调符开头,这就是说,如果模式限制为只匹配目标的开头,那么这是一个紧固模式。(也有其它结构可以使模式成为紧固的。) 美元符是一个仅在当前匹配点是目标字符串的结尾或者当最后一个字符是换行符时其前面的位置时为 TRUE 的断言(默认情况下)。如果涉及到几选一时美元符不需要是模式的最后一个字符,但应该是其出现的分支中的最后一个字符。美元符在字符类之中没有特殊含义。 美元符的含义可被改变使其仅匹配字符串的结尾,只要在编译或匹配时设定了 PCRE_DOLLAR_ENDONLY 选项即可。这并不影响 \Z 断言。 如果设定了 PCRE_MULTILINE 选项则音调符和美元符的含义被改变了。此种情况下,它们分别匹配紧接着内部 "\n" 字符的之后和之前,再加上目标字符串的开头和结尾。例如模式 /^abc$/ 在多行模式下匹配了目标字符串 "def\nabc",但正常时不匹配。因此,由于所有分支都以 "^" 开头而在单行模式下成为紧固的模式在多行模式下为非紧固的。如果设定了 PCRE_MULTILINE,则 PCRE_DOLLAR_ENDONLY 选项会被忽略。 注意 \A,\Z 和 \z 序列在两种情况下都可以用来匹配目标的开头和结尾,如果模式所有的分支都以 \A 开始则其总是紧固的,不论是否设定了 PCRE_MULTILINE。 句号(.)
    在字符类之外,模式中的圆点可以匹配目标中的任何一个字符,包括不可打印字符,但不匹配换行符(默认情况下)。如果设定了 PCRE_DOTALL 则圆点也会匹配换行符。处理圆点与处理音调符和美元符是完全独立的,唯一的联系就是它们都涉及到换行符。圆点在字符类之中没有特殊含义。 方括号([])
    左方括号开始了一个字符类,右方括号结束之。单独一个右方括号不是特殊字符。如果在字符类之中需要一个右方括号,则其应该是字符类中的第一个字符(如果有音调符的话,则紧接音调符之后),或者用反斜线转义。 字符类匹配目标中的一个字符,该字符必须是字符类定义的字符集中的一个;除非字符类中的第一个字符是音调符,此情况下目标字符必须不在字符类定义的字符集中。如果在字符类中需要音调符本身,则其必须不是第一个字符,或用反斜线转义。 举例说,字符类 [aeiou] 匹配了任何一个小写元音字母,而 [^aeiou] 匹配了任何一个不是小写元音字母的字符。注意音调符只是一个通过枚举指定那些不在字符类之中的字符的符号。不是断言:仍旧会消耗掉目标字符串中的一个字符,如果当前位置在字符串结尾的话则失败。 当设定了不区分大小写的匹配时,字符类中的任何字母同时代表了其大小写形式,因此举例说,小写的 [aeiou] 同时匹配了 "A" 和 "a",小写的 [^aeiou] 不匹配 "A",但区分大小写时则会匹配。 换行符在字符类中不会特殊对待,不论 PCRE_DOTALL 或者 PCRE_MULTILINE 选项设定了什么值。形如 [^a] 的字符类总是能够和换行符相匹配的。 减号(-)字符可以在字符类中指定一个字符范围。例如,[d-m] 匹配了 d 和 m 之间的任何字符,包括两者。如果字符类中需要减号本身,则必须用反斜线转义或者放到一个不能被解释为指定范围的位置,典型的位置是字符类中的第一个或最后一个字符。 字面上的 "]" 不可能被当成字符范围的结束。形如 [W-]46] 的模式会被解释为包括两个字符的字符类("W" and "-")后面跟着字符串 "46]",因此其会匹配 "W46]" 或者 "-46]"。然而,如果将 "]" 用反斜线转义,则会被当成范围的结束来解释。因此 [W-\]46] 会被解释为一个字符类,包含有一个范围以及两个单独的字符。八进制或十六进制表示的 "]" 也可以用来表示范围的结束。 范围是以 ASCII 比较顺序来操作的。也可以用于用数字表示的字符,例如 [\000-\037]。在不区分大小写匹配中如果范围里包括了字母,则同时匹配大小写字母。例如 [W-c] 等价于 [][\^_`wxyzabc] 不区分大小写地匹配。如果使用了 "fr" 区域的字符表,[\xc8-\xcb] 匹配了大小写的重音 E 字符。 字符类型 \d,\D,\s,\S,\w 和 \W 也可以出现于字符类中,并将其所能匹配的字符添加进字符类中。例如,[\dABCDEF] 匹配了任何十六进制数字。用音调符可以很方便地制定严格的字符集,例如 [^\W_] 匹配了任何字母或数字,但不匹配下划线。 任何除了 \,-,^(位于开头)以及结束的 ] 之外的非字母数字字符在字符类中都没有特殊含义,但是将它们转义也没有坏处。 竖线(|)
    竖线字符用来分隔多选一模式。例如,模式: gilbert|sullivan
     
    匹配了 "gilbert" 或者 "sullivan" 中的一个。可以有任意多个分支,也可以有空的分支(匹配空字符串)。匹配进程从左到右轮流尝试每个分支,并使用第一个成功匹配的分支。如果分支在子模式(在下面定义)中,则“成功匹配”表示同时匹配了子模式中的分支以及主模式的其它部分。 
    例如,如果将字符串 "the red king" 来和模式 the ((red|white) (king|queen))
     
    进行匹配,捕获的子串为 "red king","red" 以及 "king",并被计为 1,2 和 3。 
         
    内部选项设定
    PCRE_CASELESS,PCRE_MULTILINE,PCRE_DOTALL 和 PCRE_EXTENDED 的设定可以在模式内部通过包含在 "(?" 和 ")" 之间的 Perl 选项字母序列来改变。选项字母为: i 表示 <link linkend="pcre.pattern.modifiers">PCRE_CASELESS</link>
           m 表示 <link linkend="pcre.pattern.modifiers">PCRE_MULTILINE</link>
           s 表示 <link linkend="pcre.pattern.modifiers">PCRE_DOTALL</link>
           x 表示 <link linkend="pcre.pattern.modifiers">PCRE_EXTENDED</link>
     
    例如,(?im) 设定了不区分大小写,多行匹配。也可以通过在字母前加上减号来取消这些选项。例如组合的选项 (?im-sx),设定了 PCRE_CASELESS 和 PCRE_MULTILINE,并取消了 PCRE_DOTALL 和 PCRE_EXTENDED。如果一个字母在减号之前与之后都出现了,则该选项被取消设定。 这些选项改变的范围依赖于设定在模式出现的位置。子模式(在后面定义)之外的设定,其效果等同于选项在开始匹配时设定或者取消设定。下面的模式行为完全相同: (?i)abc
           a(?i)bc
           ab(?i)c
           abc(?i)
     
    它们等同于将模式 "abc" 加上选项 PCRE_CASELESS。换句话说,这种“顶层”设定适用于整个模式(除非在子模式中又有其它修改)。如果对某个选项有超过一个的顶层设定,则使用最右边的一个。 如果选项改变出现于子模式中,则效果不同。这是 Perl 5.005 的行为的一个变化。子模式中的选项改变只影响到子模式内部其后的部分,因此 (a(?i)b)c
     
    将只匹配 "abc" 和 "aBc"(假定没有使用 PCRE_CASELESS)。这意味着选项在模式的不同部位可以造成不同的设定。在一个分支中的改变可以传递到同一个子模式中后面的分支中,例如: (a(?i)b|c)
     
    将匹配 "ab","aB","c" 和 "C",尽管在匹配 "C" 的时候第一个分支会在选项设定之前就被丢弃。这是因为选项设定的效果是在编译时确定的,否则会造成非常怪异的行为。 PCRE 专用选项 PCRE_UNGREEDY 和 PCRE_EXTRA 可以和 Perl 兼容选项以同样的方式来改变,分别使用字母 U 和 X。(?X) 标记设定有些特殊,它必须出现于任何其它特性之前。最好放在最开头的位置。 子模式
    子模式由圆括号定界,可以嵌套。将模式中的一部分标记为子模式可以: 1. 将多选一的分支局部化。例如,模式: cat(aract|erpillar|)
     
    匹配了 "cat","cataract" 或 "caterpillar" 之一,没有圆括号的话将匹配 "cataract","erpillar" 或空字符串。 2. 将子模式设定为捕获子模式(如同以前定义的)。当整个模式匹配时,目标字符串中匹配了子模式的部分会通过 pcre_exec() 的 ovector 参数传递回调用者。左圆括号从左到右计数(从 1 开始)以取得捕获子模式的数目。