Perl 正则表达式语法

1. 概要

Perl正则表达式是Boost.regex 默认行为,也可以将perl传入basic_regex 构造。

boost::regex e1(my_expression);

boost::regex e2(my_expression, boost::regex::perl | boost::regex::icase);

2. 特殊字符

. [ { ( ) \ * + ? | ^ $

3. 通配符 ‘ .

在字符集之外使用时可以匹配任意单字符,除了以下两种特殊情况:

(1)NULL字符,当 标记 match_not_dot_null 被传入匹配算法中时。

(2)换行字符,当 标记 match_not_dot_newline 被传入匹配算法中时。

4. 锚点

'^'字符会匹配行的起始。

'$'字符会匹配行的终止。

5. 标记子表达式

在()之间的部分是被标记的字表达式,匹配算法会将子表达式匹配的部分分离成独立的部分。 标记子表达式可以被重复,或后向引用。

6.非标记组

  标记子表达式对于正则表达式中的成组文字部分是非常有用的,但将结果分组是有副作用的。 作为选择,可以通过 (?: expression ) 产生文字分组,但不产生标记子表达式,例如 (?:ab)+ 会重复 ab 但并不分隔出单独的子表达式。

7. 重复

  任意原子(单个字符,一个标记子表达式或一个字符组)可以通过 *, +, ? 和 {} 操作符重复。

操作符

说明

*

匹配前面的原子零次或多次

+

匹配前面的原子一次或多次

?

匹配前面的原子零次或一次

{n}

匹配前面的原子n次

{n,}

匹配前面的原子n次或更多次

{n,m}

匹配前面的原子n次到m次之间

注:如果前面的结构不能被重复,那么使用重复操作符是一个错误:

如:a(*) 会报告一个错误。

8.非贪婪重复

语法

说明

*?

匹配前面的原子零次或多次,但尽可能少地消耗输入

+?

匹配前面的原子一次或多次,但尽可能少地消耗输入

??

匹配前面的原子零次或一次,但尽可能少地消耗输入

{n,}?

匹配前面的原子n次或更多次,但尽可能少地消耗输入

{n,m}?

匹配前面的原子n次到m次,但尽可能少地消耗输入

9. Pocessive 重复

  缺省情况下,当一个重复模式不能被匹配时,引擎将回溯直至找到一个匹配。但是,有时候这种行为不是用户所期望的, 因此还有一种"pocessive"重复:它尽可能多地进行匹配且当剩下的表达式不能匹配时不允许进行回溯。

语法

说明

*+

匹配前面的原子零次或多次,但不退回

++

匹配前面的原子一次或多次,但不退回

?+

匹配前面的原子零次或一次,但不退回

{n,}+

匹配前面的原子n次或多次,但不退回

{n,m}+

匹配前面的原子n次到m次,但不退回

10. 后向引用

(1)一个转义字符跟着一个数字\n,n的范围是1-9,匹配被子表达式 n 匹配的相同字符串,如:

   ^(a*).*\1$ 匹配 aaabbaaa 但不匹配 aaabba

(2)\g转义符:

语法

说明

\g1

匹配字表达式1的内容

\g{1}

匹配字表达式1的内容:更安全的方式如\g{1234} 或\g{1}2

\g-1

匹配最后一个被打开的字表达式的内容

\g{-2}

匹配倒数第二个被打开的子表达式的内容

\g{one}

匹配名为“one”的字表达式的内容

(3)\k转义符可用于引用命名子表达式,如\k<two>将匹配名为“two”的子表达式的内容

11. 选择

(1)| 操作符匹配它的参数之一,例如 abc|def 会匹配“abc”或“def”

(2)括号可以用来对选择进行分组,例如:ab(d|ef) 会匹配 "abd" 或 "abef"。

(3)空的选择是不允许的(这通常都是错误),但如果真的需要一个空的选择,可以使用 (?:) 作为占位符,如:

|abc 不是有效的表达式,但

(?:)|abc 是有效的表达式,并且与以下表达式:

(?:abc)?? 有完全相同的作用

12. 字符集

  字符集是一个[]方括号表达式,它定义了一个字符的集合,匹配集合中的任意单个字符。包含下面的组合:

(1)单个字符:如[abc]可以匹配’a’, ’b’, 或 ’c’。

(2)字符范围:如[a-c]可以匹配’a’ 到 ’c’范围内的任意单个字符。

   对于缺省的Perl正则表达式, 如果字符x的编码值在范围两端字符y和z的编码值之间,就称字符x在范围y到z的中间。

   另外,如果在构造正则表达式时设置了 collate 标记, 那范围就是locale相关的。

(3)否定:如果方括号表达式以 ^ 字符开始,那么它匹配包含字符的补集,如:[^a-c]匹配不在a到c范围内的任意字符。

(4)字符类

   形如 [[:name:]] 的表达式匹配命名字符类"name",例如 [[:lower:]] 任意小写字符。 参见字符类名称表。

(5)对照元素

   形如 [[.col.]] 的表达式匹配对照元素 /col/。对照元素是任意的单个字符,或对应于某个单个单元的字符序列。 对照还可以用作范围的端点,例如 [[.ae.]-c] 匹配字符序列"ae",和任意的单个字符在范围"ae"到c之间, 其中"ae"被当前locale处理为单个对照元素。

   作为扩展,对照元素可以通过其 符号名 指定,例如:

[[.NUL.]] 匹配一个 \0 字符。

(作为对照元素名称时下面的情况被当作合法的连字:

"ae", "Ae", "AE", "ch", "Ch", "CH", "ll", "Ll", "LL", "ss", "Ss", "SS", "nj", "Nj", "NJ", "dz", "Dz", "DZ", "lj", "Lj", "LJ". )

(6)等价类

形如 [[=col=]] 的表达式匹配主排序关键字等同于对照元素 col 的任意字符或对照元素,其中名字为 col 的对照元素可以是一个 符号名。主排序关键字忽略大小写、重音或特定区域(locale)的裁剪(tailorings); 所以如 [[=a=]] 匹配下面的字符:a, À, Á, Â, Ã, Ä, Å, A, à, á, â, ã, ä 和 å。 不幸的是这个实现依赖于平台的对照(collation)和地区(localization)支持; 这个特性并不能很好地可移植工作于所有的平台,甚至一个平台上的所有区域(locale)。

(7)转义字符

   任意匹配单个字符或单个字符类的转义序列都可以定义在字符类中。例如[\[\]] 可以匹配 [ 或 ] ,而 [\W\d] 可以匹配任何“数字”字符或者任何不是"单词"的字符。

(8)组合

   所有上面的都可以在一个字符类声明中被组合,例如 [[:digit:]a-c[.NUL.]]。

13. 转义符

(1)任意特殊字符前面加转义符都匹配自己。

(2)下面的转义序列和单个字符同义

转义符

字符

\a

\a

\e

0x1B

\f

\f

\n

\n

\r

\r

\t

\t

\v

\v

\b

\b(仅在字符类声明中使用)

\cX

一个ASCII转义序列,字符码点为 X % 32

\xdd

一个十六进制转义序列,匹配码点为0xdd的单个字符。

\x{dddd}

一个十六进制转义序列,匹配码点为0xdddd的单个字符。

\0ddd

八进制转义序列,匹配码点为0ddd的单个字符。

\N{name}

匹配 符号名name的单个字符。

(3)“单字符” 字符类

转义序列

等价于

\d

[[:digit:]]

\l

[[:lower:]]

\s

[[:space:]]

\u

[[:upper:]]

\w

[[:word:]]

\h

水平空白

\v

垂直空白

\D

[^[:digit:]]

\L

[^[:lower:]]

\S

[^[:space:]]

\U

[^[:upper:]]

\W

[^[:word:]]

\H

非水平空白

\V

非垂直空白

(4)字符属性

下面表格中的字符属性名称都等价于字符类中使用的名字。

形式

说明

等价的字符集形式

\pX

匹配任意具有属性X的字符

[[:X:]]

\p{Name}

匹配任意具有属性Name的字符

[[:Name:]]

\PX

匹配任意不具有属性X的字符

[^[:X:]]

\P{Name}

匹配任意不具有属性Name的字符

[^[:Name:]]

 例如 \pd 匹配任意的"数字"字符,和 \p{digit} 作用是一样的。

(5)单词边界

下面的转义序列匹配单词的边界:

\< 匹配单词的起点

\>匹配单词的终点

\b匹配单词的边界(起点或终点)

\B只有不在边界时才匹配。

(6)缓冲区边界

下面的转义序列匹配缓冲区边界:这里的"缓冲区"指用于匹配的全部输入文本(注意,^和$可以用于匹配文本中的行)。

\` 匹配缓冲区的起点。

\' 匹配缓冲区的终点。

\A 匹配缓冲区的起点(同 \\\` 一样)。

\z 匹配缓冲区的终点(同 \\' 一样)。

\Z 匹配一个零长度的断言,包括缓冲区结尾处可能存在的空行:等价于正则表达式 (?=\v*\z)。注意,这与 Perl 中匹配 (?=\n?\z) 的行为有一些微妙的不同。

(7)持续转义

   序列 \G 只在上次匹配结尾或匹配文本的起点(如果前面没有匹配)。 当你要迭代文本中所有的匹配,并且每个子序列都从上一次结束时开始匹配的话,这个转义是很有用的。

(8)引用转义

   转义序列 \Q 开始一个"被引用序列":所有后面的字符都被当作字面对待,除非正则表达式结束或碰到 \E。 例如,表达式:\Q\*+\Ea+ 可以匹配如下:

   \*+a

   \*+aaa

(9)Unicode转义

   \C 匹配一个单一的码表:在 Boost.Regex 中这和"."操作符的作用是完全相同的。

   \X 匹配一个组合字符序列:任意非组合字符跟上一个零或多个组合字符的序列。

(10)匹配行末符

    转义序列 \R 匹配任何行末符序列,特别地,它等同于表达式 (?>\x0D\x0A?|[\x0A-\x0C\x85\x{2028}\x{2029}]).

(11)回退一些文本

    \K 将$0的开始位置重置为当前文本位置:换言之,\K 左边的所有东西被"退回"且不作为该正则表达式的匹配部分。 $` 也被相应更新。

    例如,foo\Kbar 用于匹配文本 "foobar" 时,将对 $0 返回匹配 "bar",对 $` 返回 "foo"。 这可以被用于模拟可变宽度的后向环视断言。

(12)其他转义

    其它转义序列匹配被转义的字符,例如 \@匹配 '@'。

14. Perl 扩展模式

Perl扩展的正则表达式语法都以 (? 开始。

(1)命名子表达式: (?<NAME>expression),或者 (?'NAME'expression)

(2)引用命名子表达式: 通过\g{NAME} 或 \k<NAME>后向引用,也可以在一个 Perl 格式化串或在 match_results 成员函数中通过名字来引用以进行搜索和替换的操作。

(3)注释

(?# ... ) 作为注释,里面的内容被忽略。

(4)修饰

  (?imsx-imsx ... ) 改变在模式中perl修饰符是否起作用,从块第一次被遇到的点开始起作用,直到遇到结束 =)=。 '-' 之前的字母打开perl修饰符,后面的字母关闭。

  (?imsx-imsx:pattern) 只将特定的修饰符应用于指定的模式。

(5)非标记分组

  (?:pattern) 进行字面分组,但不产生额外的子表达式。

(6)分支重置

  (?|pattern) 在 pattern 内的每个 "|" 选择符开始重置子表达式计数。

  该结构之后的子表达式计数由具有最大子表达式数量的分支决定。当你想用单个子表达式索引捕获多个可选匹配之一的时候,可使用该结构。例如:

  / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x

  # 1 2 2 3 2 3 4

(7)前向匹配

  (?=pattern) 当模式匹配时成功,但不消耗字符

  (?=exp)也叫“零宽度正预测先行断言”,它断言自身出现的位置的后面能匹配表达式exp,比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。

  (?!pattern) 当模式不匹配时成功,但不消耗字符。

  “零宽度负预测先行断言”(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。

  前向匹配的典型用法是创建两个正则表达式的逻辑与,例如一个密码必须包含一个小写字符, 一个大写字符,一个标点符号,长度至少6个字符,那么表达式是:

  (?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}

(8)后向匹配

(?<=pattern) 只有当模式能够被当前位置之前的字符匹配时才成功(模式必须是固定长度),但并不消耗字符。

(?<=exp)也叫“零宽度正回顾后发断言”,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。

(?<!pattern) 只有当模式不能够被当前位置之前的字符匹配时才成功(模式必须是固定长度),但并不消耗字符。

“零宽度负回顾后发断言” (?<!pattern),来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字

(9)独立子表达式

(?>pattern) pattern 独立于外围模式地被匹配,表达式决不会被回溯到 pattern 中。 独立子表达式通常用于改善性能;只有最好可能的匹配才会被考虑,如果表达式不能作为整体被匹配,那就没有匹 配。

(10)递归表达式

   (?N) (?-N) (?+N) (?R) (?0)

   (?R) and (?0) 递归至整个模板的开始。

   (?N) 重复执行子表达式/N/,例如 (?2) 将递归至子表达式2。

   (?-N) 和 (?+N) 是相对递归,因此如 (?-1) 将递归至被声明的最后一个子表达式,而 (?+1) 则递归至被声明的下一个子表达式。

(11)条件表达式

1. (?(condition)yes-pattern|no-pattern) 当 condition 成立时试图匹配 /yes-pattern/,否则试图匹配 /no-pattern/。

2. (?(condition)yes-pattern) 当 condition 成立时试图匹配 /yes-pattern/,否则直接失败。

3. condition 可以是一个前向匹配断言, 或者是一个标记子表达式序号(当子表达式匹配时条件为真), 或是一个递归的索引(当我们在指定递归中直接执行时条件为真)。

4. 可能的谓词:

(?(?=assert)yes-pattern|no-pattern) 如果前向匹配成功则执行 /yes-pattern/,否则执行 /no-pattern/。

(?(?!assert)yes-pattern|no-pattern) 如果前向匹配不成功则执行 /yes-pattern/,否则执行 /no-pattern/。

(?(R)yes-pattern|no-pattern) 如果是在某个递归的内部执行,则执行 /yes-pattern/,否则执行 /no-pattern/。

(?(RN)yes-pattern|no-pattern) 如果是在某个到子表达式/N/的递归内部执行,则执行 /yes-pattern/,否则执行 /no-pattern/。

(?(DEFINE)never-exectuted-pattern) 定义一个从不执行也不匹配任何字符的代码块: 通常用于定义一个或多个从模板其它地方引用的命名子表达式。

15. 操作符优先级

(1)对照相关的方括号字符 [==] [::] [..]

(2)转义字符 \

(3)字符集(方括号表达式) []

(4)分组 ()

(5)单字符-ERE重复 * + ? {m,n}

(6)连接

(7)锚点 ^$

(8)选择 |

16. 最优匹配

  如果将正则表达式当作有向(可能循环)图,那么最优匹配就是在匹配输入文本过程中按照深度优先搜索找到的第一个匹配。

字符类名称表:

名称

是否POSIX标准名称

说明

alnum

yes

任意 单词-数字 字符

alpha

yes

任意单词字符

blank

yes

非行分隔符的任意空白字符

cntrl

yes

任意控制字符

d

no

任意数字字符

digit

yes

任意数字字符

graph

yes

任意图形字符

l

no

任意小写字符

lower

yes

任意小写字符

print

yes

任意可打印字符

punct

yes

任意标点字符

s

no

任意空白字符

space

yes

任意空白字符

unicode

no

任意码点高于255的字符

u

no

任意大写字符

upper

yes

任意大写字符

w

no

任意单词字符(字母、数字和下划线)。

word

no

任意单词字符(字母、数字和下划线)。

xdigit

yes

任意十六进制数字字符。