摘自 chapter 9
一个正则表达式就像一个数学表达式。它由原子和运算符组成。原子指定要查找的内容以及在文本中进行匹配的位置。运算符不是所有表达式都必须的,它把原子结合到复杂的表达式中.
正则表达式=原子+运算符
9.1) 原子
正则表达式中的原子可为如下5种类型:
单个字符、点、类、锚、向后引用。
单个字符-出现在正则表达式中的时候,它与自己进行匹配。
点---> 一个点匹配除了换行符(\n)以外的任意单个字符. 这种全体匹配功能使其成为正则表达式操作中一种功能强大的元素.但从其自身而言,它什么也不能做,因为它匹配所有元素.它的强大之处在于与其他原子结合而创造一个表达式的能力. 如: a. 匹配 ap , aq , aA, a0 但不匹配 Aa.
类原子定义了一个ASCII字符集. 其中任意一个都要匹配文本中的任意字符.匹配过程中使用的该字符要用括号括起来. 如: 类[ABC]将匹配 A,B或C.
类集合是一种很强大的表达式元素.它的强大使其可以扩展出三种额外的表示: 范围,排除,转义字符. 文本范围由破折号(-)指出.因此[a-d]将匹配a,b,c或d.
有时候要指定哪个字符被排除在集合外--也就是指定其余集. 可使用exclusion实现它,这是一种UNIX的非运算符(^). 比如要指定任意非元音字符--> [^aeiou],非数字 [^0-9].
第三个扩展出的标记是转义字符(\).在匹配字符为其他两种之一的时候使用它. 例如: 要匹配一个元音或破折号,可使用转义符指出破折号是一个字符,不是一个范围标记. 表达式编码为: [aeiou\-].
以下是几个类原子的例子:
[A-H] ----> [ABCDEFGH]
[A-Z] ----> 任意大写字母
[0-9] ----> 任意数字
[[a] ----> [ 或 a
[0-9\-] --> 数字或破折号
[^AB] ----> 除A,B以外的任意字符
[A-Za-z] -> 任意字母
[^0-9] ---> 除数字外任意字母
[]a] ----> ] 或 a
[^\^] ----> 除^之外的任意字符
锚---是在将模式与字符串的特定部分进行行对齐时使用的原子.换句话说,锚不匹配文本,而是定义模式中下一个字符在文本中必须出现的位置. 锚有四中类型: 行首(^),行尾($),单词开头(\<),单词结尾(\>).
锚原子经常在结合中使用. 比如要匹配一个一Q开头的一个字符串,表达式编码为: ^Q.以g结尾的单词: g\>.
注意:
正则表达式开头的^字符是一个锚,含义为当前行的行首. 在其他地方,它作为一个文本字符与自己进行匹配.
正则表达式结尾的$字符是一个锚,含义为当前行的行尾. 在其他地方,它作为一个文本字符与自己进行匹配.
向后引用
可以把文本暂时保存在9个存储缓冲区内的其中一个. 这样,我们可以使用一个向后引用,引用保存在缓冲区内的文本. 使用转义符和范围1-9的数字对向后引用进行编码: 1\2\...\9
向后引用用于将当前或目标缓冲区内的文本和保存在系统的9个缓冲区其中之一中的文本进行匹配. 在后面讨论存储运算时,进一步分析.
9.2) 运算符
为增强正则表达式的功能,可将原子和运算符结合起来.
正则表达式可以分5种类型:序列运算符,替换运算符,重复运算符,组运算符,保存运算符.
9.2.1 序列
序列运算符为空. 它的含义是: 如果原子序列,如字符序列,出现在正则表达式中,则暗示在原子间有一个不可见的序列运算符.以下是序列运算符的几个例子:
dog ----> 匹配模式"dog"
a..b ----> 匹配a,接着2个任意字符,匹配b
[2-4][0-9] ----> 匹配20-49之间的数字
[0-9][0-9] ----> 匹配任意2个数字
^$ ----> 匹配空行
^.$ ----> 匹配只有一个字符的行
[0-9]_[0-9] ----> 匹配由"_"分隔的2个数字
9.2.2 替换
替换运算符(|) 用于定义一个或多个替代物. 例如:如果要选择A或B,则表达式为 A|B . 替换可如前例一样用于单个原子. 但它通常用于选择两个或多个字符序列或字符组. 也就是说原子通常是序列. 对于单个替换,建议使用类运算符.
UNIX | unix ----> 匹配"UNIX"或"unix"
ABCD | abcd ----> 匹配"ABCD"或"abcd"
9.2.3 重复
重复运算符是转义括号(\{...\})的集合,它包含由逗号分隔的2个数字的集合.它指定重复运算符前的原子或表达式的重复次数.第一个数字(m)指出前面的原子在文本中出现的最少次数;第二个数字(n)指出它出现的最大次数. 例如,重复运算符\{2,5\}指出前面的原子被重复2到5次.
A\{3,5\} ---> 匹配"AAA","AAAA","AAAAA"
1). 重复的基本形式
m,和n的取值形式是可选的,但必须至少指定一个. 也就是说,可以只出现其中的一个.
如果只有一个重复值(m)被括在括号内,则前面的原子必须精确重复m次---不能多或少. 例如:
\{3\} ---> 前面的原子出现且只能出现3次.
如果最小值(m)后面跟一个逗号,但没有最大值,则前面的原子必须至少出现m次,但可以多于m次.例如:
\{3,\} ---> 前面的原子可以重复大于等于3次以上,但不能少于3次.与上例的差别在于多一个逗号.
如果最大值前面有一个逗号,但没有最小值,则前面的原子出现最多n次,不能再多.
\{,3\} ---> 前面的原子出现0-3次但不能再多了.
2). 缩写形式的运算符
UNIX为三种常用的重复形式提供了特殊的缩写运算符. 星号(*)可以用来重复一个原子0或多次(等同于\{0,\}). 加号(+)用于指定原子必须出现一次或多次(等同于\{1,\}. 问号标记(?)用于只重复一个模式0或1次(等同于\{0,1\}).
例如:
ba* ---> 匹配b,ba,baa,baaa,...
b.* ---> 匹配b,ba...,bz,baa...bzz,baaa,bzzz
.* ---> 匹配0或多个字符
+* ---> 匹配一个或多个字符
注意: 正则表达式中的(*)和(?)于通配符中的(*)和(?)的意义是不同的.
3). 贪婪模式匹配
UNIX中的重复运算符是称为贪婪算法的常用算法类的一部分. 贪婪算法的设计目的为最大化其操作.在模式匹配中,贪婪意味着使用匹配一个模式的最长的字符串.
当使用一个包含重复运算符的正则表达式的时候,重复部分会试图使结果尽可能多的匹配文本.
看下面这个例子:
-------------------------------------------
字符串 正则表达式
XAYXFOONFOOAX A.*FOO
-------------------------------------------
XAYXFOONFOOAX
A.*FOO 不匹配
-------------------------------------------
XAYXFOONFOOAX
A.*FOO 开始匹配
-------------------------------------------
XAYXFOONFOOAX
A.*FOO 贪婪匹配
-------------------------------------------
XAYXFOONFOOAX
A.*FOO 最终匹配(贪婪)
-------------------------------------------
匹配得到的字符为: AYXFOONFOO (贪婪)
9.2.4 组运算符
组运算符使一对圆括号. 当一组字符被括在圆括号内,则下一运算符应用于整个组,而不止是前面的字符
例如:
A(BC)\{3\} ---> 匹配 ABCBCBC
(F(BC)\{2\}G)\{2\} ---> 匹配 FBCBCGFBCBCG
9.2.5 保存
保存运算符是转义圆括号集合 \(...\),它把匹配的文本字符串复制到9个缓冲区的其中一个,以便后面引用. 在一个表达式内,第一个被保存的文本被复制到缓冲区1,第二个被复制到缓冲区2, 等等...最多可到第九个.
一旦文本被保存,就可以使用向后引用来引用它.
下面创建一个比较典型的保存命令的例子,这个例子创建一个匹配以相同字母开头和结尾的文本的模式. 这个问题的难点在于我们不知道开始和结束的字母是什么. 解决方案是把文本字符串的第一个字母保存在一个缓冲区内,然后使用该缓冲区类匹配字符串的最后一个字符.
-----------------------------------------------------------------------
字符串 NACDEXGHIJABC 正则表达式 \([A-Z]\).*\1
-----------------------------------------------------------------------
NACDEXGHIJABC
\([A-Z]\).*\1 N保存至缓冲区1
-----------------------------------------------------------------------
NACDEXGHIJABC
\([A-Z]\).*\1 无匹配
-----------------------------------------------------------------------
NACDEXGHIJABC
\([A-Z]\).*\1 A保存至缓冲区1
-----------------------------------------------------------------------
NACDEXGHIJABC
\([A-Z]\).*\1 贪婪匹配
-----------------------------------------------------------------------
NACDEXGHIJABC
\([A-Z]\).*\1 匹配缓冲区1内的文本
-----------------------------------------------------------------------
小结:
类原子和点原子至定义一个单个字符,长度为1,锚原子定义没有字符,长度为0.
特殊字符(^)有两种不同的用法. 如果它在一个集合方括号内[^...],则含义为"非","取余".如果在一个正则表达式的开头(方括号外面),它就是一个匹配行首的锚.
类原子的范围含义是基于ASCII字符的字符范围,如果要定义30-39之间的数字不能用[30-39],而是需要一个带有两个原子的序列的正则表达式: 3[0-9]