一个正则表达式 (regular expression ) 描述了一类字符串。它是匹配特定字符串而不匹配其他的字符串的一个模式。
译注:grep 缺省支持 BRE,通过指定 -E 选项来支持 ERE,历史上的 egrep 和 fgrep 已经合并入 grep 中。ed、sed 支持 BRE,lex、AWK 支持 ERE。
这个手册页主要描述 ARE。提供 BRE 主要是为了在一些老程序中反向(backward)兼容;它们将最后讨论。POSIX ERE 基本上是 ARE 的一个真子集。在 ERE 中不存在的 ARE 的特征将被指示出来。
实现 Tcl 正则表达式使用了 Henry Spencer 写的包,基于 POSIX 1003.2 规定和一些(不是全部) Perl5 扩展 (感谢 Henry!)。下面的许多正则表达式描述是原封不动的从他的手册页复制过来的。
译注:Perl5 的正则表达式也是从 Henry Spencer 所写的包演变而来。
一个 ARE 是一个或多个由`|'分隔的分支(branch)(构成的),它匹配与任何一个分支匹配的一个字符序列。
一个分支是零或多个串联起来的约束(constraint)或定量原子(quantified atom)(构成的)。它与每个构件(约束或定量原子)所匹配的任何字符序列的一个串联相匹配,组成这个字符序列的串联的第一个字符序列与这个分支的第一个构件相匹配,第二个字符序列与第二个构件相匹配,以此类推。一个空分支匹配空串。
一个定量原子是可能跟随一个单一的定量符 (quantifier) 的原子。不加定量符,它匹配这个原子的一个匹配。定量符和它所定量的原子的匹配如下:
使用 { 和 } 的形式叫做束缚(bound)。数 m 和 n 是无符号十进制整数,允许的值从 0 到 255(包括0 及 255)。
原子是下列之一:
译注:使用圆括号来组合原子。例如,ab* 被识别为原子 a 和原子 b 的闭包 b* 的串联 a(b)*,而不是原子 a 和原子 b 的串联 ab 的闭包 (ab)*。捕获的意思是把在圆括号中的子表达式所匹配的字符序列保存下来,由后续的后引用去使用。
约束 (constraint) 在指定条件满足的时候匹配一个空串。一个约束不能跟随一个定量符。简单的约束如下;其他的在以后的 ESCAPES 转义 章节中介绍。
译注:约束的术语叫锚定
前行约束不能包括后引用(参见后面),并且其中的所有圆括号被认为是非捕获的。
一个 RE 不能结束于`\'.
如果在这个列表中的两个字符被`-'分割,这是在归并序列(collating sequence)中这两个字符之间(包括二者)的字符的完整范围的简写,例如,[0-9] 在 ASCII 中匹配任何十进制数字。两个范围不能共享同一个端点,比如 a-c-e 是非法的。范围是很依赖于整理序列的,可移植程序应该避免依靠它们。
译注:整理元素 -- 用来确定字符或宽字符字符串的逻辑次序的最小实体。一个整理元素的组成要么是一个单一字符,要么是被整理为一个实体的两个或更多字符。由当前地域(locale)中的 LC_COLLATE 类属的值确定整理元素的当前设置。
译注:整理序列 -- 当前地域中的 LC_COLLATE 类属的设置确定 整理元素的相对次序。这个字符次序定义所有整理元素的相对位置,在这个次序中每个元素都占有一个唯一的位置。
要在这个列表中包括一个文字的 ] 或者 - ,最简单的方法是把它包围在 [. 和 .] 中使它成为一个整理元素(见后)。可替代的,使它成为第一个字符(跟随在可能的‘^’的后面),或(专属 ARE) 加以 ‘\fR’先导。可选的,对于‘-’,使它成为最后的字符,或一个范围的第二端点。要使用一个文字 - 作为一个范围的开始端点,可以使它成为一个整理元素或(专属 ARE) 加以‘\’先导。除了这些例外、一些使用 [ (参见下段)的组合、和转义,在一个方括号表达式中的所有其他特殊字符失去其特殊意义。
在一个方括号表达式当中,在 [. 和 .] 当中包围一个归并元素(collating element)(一个字符、一个多字符序列被整理为如同一个单一字符,或给二者的一个整理序列名字)表示这个整理元素的一个字符序列。这个序列是这个方括号表达式列表中的一个单一元素。在有多字符整理元素的地域中,一个方括号表达式可以匹配多于一个字符。 所以(潜藏的),即使在方括号表达式中未出现多字符整理元素,以 ^ 为开始的一个方括号表达式仍可以匹配多字符整理元素! (注意:Tcl 目前没有多字符整理元素。这些信息只是用来解释概念。)
例如,假定整理序列包含一个 ch 多字符整理元素,则 RE [[.ch.]]*c (后面跟随着 c的零或多个 ch) 匹配`chchcc'的最先的5个字符。还有 [^c]b 匹配整个`chb'(因为 [^c] 匹配多字符 ch)。
在一个方括号表达式中,在 [= 和 =] 当中包含的一个整理元素是一个equivalence class 等价类,表示等价于这个整理元素的所有整理元素的字符序列,包括它自身。(如果没有其他等价的整理元素,与在分界符`[.'和`.]'中包含一样对待。) 例如,如果 o 和 是一个等价类的成员,则`[[=o=]]'、`[[==]]'、和`[o]'都是同义词。一个等价类不能是一个范围的端点。 (注意:Tcl 目前只实现了 Unicode 地域。它不定义任何等价类。上面的例子只是用来解释概念。)
在一个方括号表达式中,在 [: 和 :] 中包含的一个character class 字符类 的名字表示属于这个类的所有字符的列表(不是所有整理元素!)。标准字符类有:
alpha一个字母 upper一个大写字母 lower一个小写字母 digit一个十进制数字 xdigit一个十六进制数字 alnum一个 alphanumeric (字母或数字) print一个 alphanumeric (同于 alnum) blank一个空格或 tab 字符 space在显示的文本中产生白空格的一个字符 punct一个标点字符 graph有图形表示的一个字符 cntrl一个控制字符
一个地域可以提供其他的字符类。 (注意:Tcl 目前只实现了一个地域:Unicode 地域。) 一个字符类不能用做一个范围的端点。
方括号表达式有两个特殊情况: 方括号表达式 [[:<:]] 和 [[:>:]] 是约束,分别匹配在一个字开始处和结束处的空串。定义一个字为既没有前导的又没有尾随的单词字符的单词字符的一个序列。一个单词字符是一个 alnum 字符或一个下划线(_)。这些特殊的方括号表达式已被淘汰;ARE 用户应当转而使用约束转义(见后)。
字符录入转义 (Character-entry escapes) (专属 ARE) 的存在简便了在 RE 中指定一个非打印和其他非常规字符:
十六进制数字是 `0'-`9', `a'-`f', 和`A'-`F'. 八进制数字是 `0'-`7'.
字符录入转义总是被接受为普通字符。例如, \135 是ASCII中的 ] 而 \135 不终结一个方括号表达式。但是要小心,一些应用(例如 C 编译器)在正则表达式包得到它们之前要自己解释这些序列,这可能就要求写两次(四次 (quadrupling),等等) `\'。
类简写转义 Class-shorthand escapes (专属 ARE) 为特定的通用字符类提供简写:
W在方括号表达式中,没有外面的方括号的`\d', `\s', 和 `\w' ,还有 `\D', `\S', 和 `\W' 都是非法的。 (所以,等价于[a-c[:digit:]] 的 [a-c\d] 和等价于 [a-c^[:digit:]] 的[a-c\D] 是非法的)
约束转义 constraint escape (AREs only) 是如果指定条件满足则匹配空串的一个约束,它被写成一个转义:
同于上面规定的 [[:<:]] 和 [[:>:]] ,字定义为既没有前导的又没有尾随的单词字符的一个序列。 一个单词字符是一个 alnum 字符或一个下划线(_)。 在方括号表达式中,约束转义是非法的。
一个后引用(专属 ARE) 匹配的字符串与用数字指定的在圆括号中的子表达式所匹配的字符串相同,所以(例如) ([bc])\1 匹配 bb 或 cc 而不是 ‘bc’。在 RE 中,子表达式必须全部在后引用的前面。以前导的圆括号(左圆括号)的次序给子表达式编号。非捕获圆括号不定义子表达式。
译注:后引用是原属 BRE 的特征,ERE 无此特征。例如,表达式 ^(.*)\1$ 匹配由同一个字符串的两个毗连的出现组成的一行,而表达式 (a)*\1 不匹配 a。(a)(b)\1 匹配 aba,(a)(b)\2 匹配 abb,(a(b))\1 匹配 abab,(a(b))\2 匹配abb。(a)\1 等价于 a{2,2}。
在八进制字符录入转义和后引用之间有一个历史遗留的二义性,只能象上面提示的那样用启发式的方法来解决。一个前导的零总是指示一个八进制转义。一个单一的非零数字,不跟随着其他数字,总是接受为一个后引用。不以一个零为开始的一个多数字序列如果在一个合适的子表达式后面,则被接受为一个后引用 (比如给出的后引用的序号在合法范围内),否则被接受为一个八进制转义。
一般通过应用相关的方式指定使用的 RE 的风格。但是,可以用指示符(director)来屏弃它们。如果某种风格的一个 RE 以‘***:’为开始,则 RE 的剩余部分是一个 ARE。如果某种风格的一个 RE 以‘***=’为开始,则 RE 的剩余部分被接受为一个文字串,并且其中的所有字符被认为是普通字符。
一个 ARE 可以以embedded options 嵌入选项为开始: 一个序列 (?xyz) (这里的 xyz 是一个或更多的字母字符) 指定影响 RE 剩余部分的选项。它们提供和屏弃由应用指定的任何选项。可获得的选项字母有:
嵌入选项影响的序列被 ) 终结。它们只在一个 ARE 的开始处有效,此后不可以在其中使用。
除了通常的(紧凑) RE 语法,其中所有字符都有意义,还有一个展开语法,在所有风格的 RE 中都可以使用 -expanded 开关来获得它,或者在 ARE 中使用嵌入的 x 选项。在展开语法中,忽略白空格和在 # 和随后的换行(或 RE 结束)之间的所有字符,这就允许了在一个复杂的 RE 中进行分段和注释。有对这些基本规则的三个例外:
保留有前导`\'的白空格或 `#'
保留在方括号表达式中的白空格或 `#'
在多字符符号如 ARE `(?:' 或 `\(' 中间的白空格或注释是非法的
展开语法中的白空格是 blank、tab 、和属于空格字符类的任何字符。
最后,在 ARE 中,在方括号表达式外面,序列 `(?#ttt)' (这里的 ttt 是不包含 `)' 的任何文本) 是一个注释,它将被完全忽略。同样,不允许它在多字符符号如 `(?:'中间的出现。这种注释是历史产物而不是很有用的设施,它的使用被淘汰了;应使用展开语法来替代。
如果应用(或一个启始的 ***= 指示符)指定用户的输入被作为一个文字串而不是一个 RE 来对待,则不能获得这些元语法扩展。
译注:零个或多个字符的一个序列被称为与 RE 匹配的条件是在这个序列中的字符对应于这个模式定义的一个字符序列。
译注:对一个匹配的序列的查找开始于一个字符串的开始处,停止于找到第一个匹配字符串的时候,这里定义第一个的意思为“字符串中最早开始的”。如果模式允许匹配的字符有可变的数目,因此在这个点开始的序列多于一个,则匹配最长的那个序列。例如: RE bb* 匹配 abbbc 中的第2到第4个字符,而 RE (wee|week)(knights|night) 匹配 weeknights 的所有10个字符。
译注:与整个匹配是最长的最左匹配相一致,从左到右的每个子模式,匹配最长的可能的字符串。为此,一个空串被认为比根本没有匹配长。例如,针对(against) abcdef 匹配 RE (.*).* ,子表达式 (1) 是 abcdef,而针对 bc 匹配 RE (a*)*,子表达式 (1) 是空串。
译注:通过向每个子表达式递归的提供最左最长匹配来确定什么(子)字符串对应于子表达式是可能的,而附带条件是整体匹配是最左的、最长的。例如,针对acdacaaa 匹配 (ac*)c*d[ac]*1 匹配出 acdacaaa (这里 1=a); 而简单的给 (ac*) 匹配最长的将生成 1=ac,但整体匹配将变小 (acdac)。概念上,实现必须检查每种可能的匹配,并在生成的最左最长的总体匹配中,为最左子表达式挑出一个最长的匹配(子串)并以此类推。注意,这意味着子表达式的匹配是上下文相关的: 在一个很大的 RE 中的一个子表达式所匹配的字符串可能与它作为一个独立的 RE 时不同,还有,即使在类似的字符序列中,在同一个很大的 RE 中的同一个子表达式的两个实例可能匹配不同的长度。例如,在 RE (a.*b)(a.*b) 中,两个完全相同的子表达式将分别的匹配 accbaccccb 的四个和六个字符。
如果一个 RE 能匹配一个给定字符串中的多于一个的子串,RE 匹配在这个字符串中最先开始的子串。如果 RE能匹配的在这一点上开始的子串多于一个,它的选择决定于它的偏好(preference): 要么是最长的子串,要么是最短的子串。
多数原子和所有约束,都没有偏好。一个有圆括号的 RE 与 RE 有相同的偏好(有可能没有)。一个有 {m} 或 {m}? 定量符的定量原子与原子自身有相同的偏好(有可能没有)。一个有其他平常的定量符的定量原子(包括在 {m,n} 中 m 等于 n) 偏好最长的匹配。一个有不贪婪定量符的定量原子(包括在 {m,n}? 中 m 等于 n 的情况) 偏好最短的匹配。一个分支与在它的里面的第一个定量原子有相同的偏好。用 | 操作符连接起来的一个由两个或多个分支组成的 RE 偏好最长的匹配。
取决于匹配整个 RE 的规则所强加的约束,基于可能子串的表现,子表达式可以匹配最长或最短的可能子串,在 RE 中开始较早的子表达式优先于开始较晚的。注意,外部的子表达式优先于其中的构件子表达式。
注意,可以分别的使用定量符 {1,1} 和 {1,1}? 在子表达式或整个 RE 上强制最长和最短偏好。
用字符数而不是整理元素数来测量匹配长度。一个空串被当作比根本没有匹配长 ,例如 bb* 匹配 `abbbc'中间的三个字符, (week|wee)(night|knights) 匹配 `weeknights'的所有10个字符,在针对(against) abc 匹配 (.*).* 的时候圆括号中的子表达式匹配所有这三个字符,而在针对 bc 匹配 (a*)* 的时候整个 RE 和圆括号中子表达式都匹配一个空串。
如果指定了大小写无关匹配,效果如同所有字母的大小写区别都消失了。当存在大小写区别的一个字符在方括号表达式外面作为一个普通字符出现的时候,它被有效的转变成包含大小写二者的一个方括号表达式, 所以 x 变成了`[xX]'。当它出现在一个方括号表达式中,把它对应的所有大小写添加到方括号中,所以[x] 变成 [xX]而 [^x] 变成 `[^xX]'。
如果指定了换行敏感匹配,则 . 和使用 ^ 的方括号表达式永不匹配换行字符(所以除非 RE 显式安排,否则永不会跨越换行来进行匹配),并且 ^ 和 $ 除了分别匹配字符串的开始和结束之外,还分别的匹配在换行之后和之前的空串。ARE A 和 Z 继续只匹配字符串的开始和结束。
如果指定了部分换行敏感,这将致使 . 和方括号表达式成为换行敏感匹配,但不影响 ^ 和‘$’。
如果指定了反向部分换行敏感,这将致使 ^ 和 $ 成为换行敏感匹配,但不影响 . 和方括号。这不是很有用,提供它只是为了对称。
专属 ARE 并且实际上与 POSIX ERE 不相容的特征是在方括号表达式中的 \ 不失去它的特殊意义。所有其他 ARE 特征使用的语法在 POSIX ERE 中是非法的,或着有未定义或未指定的效果;指示符的 *** 语法同样不属于 BRE 和 ERE 二者的 POSIX 语法。
许多 ARE 扩展取自 Perl,为了整理它们而进行了一些变更,还有一些 Perl 扩展未提供。要注意的不相容包括:‘\b’、‘\B’,缺乏对尾随的换行的特殊对待,为受换行敏感匹配影响的 RE 增加了方括号表达式补全,在先行约束中对圆括号和后引用的限制,和最长/最短匹配的匹配语义。
自从这个包的一个早期的 beta 测试版本做了变更以来,RE 的匹配的规则包含正常的和非贪婪的定量符二者。(新规则更加简单和清晰,而不在猜测用户的真实意图上费很大力气。)
Henry Spencer 的原始的 1986 regexp 包,仍被广泛的使用(例如,在 Tcl 8.1 之前的发行中),它实现了今天的 ERE 的一个早期版本。在 regexp 的近似 ERE (简写为 RRE)和 ARE 之间有四点不相容: In roughly increasing order of significance:
在 ARE 中跟随着一个数字的 { 是一个束缚的开始,而在 RRE 中,{ 总是一个普通字符。这样的序列是少见的,并且经常导致一个错误,原因是随后的字符看起来不象一个有效的束缚。
在 ARE 中,在`[]'内 \ 保持是一个特殊字符,所以在`[]'内一个文字 \ 必须写成`\\'。在 RRE 中,在[]内 `\\' 也给出一个文字 \,但只有真正的偏执狂程序员才例行公事的双写反斜杠。
ARE 为 RE 报告最长的和最短的匹配,而不是按指定的查找次序找到的第一个匹配。这可能影响寄希望于第一个匹配不被报告的一些 RRE。(废弃了为快速匹配而优化查找次序的 RRE 细致工艺(ARE 并行的检查所有可能的匹配,并且它们的性能在很大程度上不敏感于它们的复杂性),而为故意的找寻非最长或最短的一个匹配而开发的查找次序需要重写。)