模式匹配 ========= OushuDB 提供了三种实现模式匹配的方法: 传统SQL的LIKE操作符、SQL99 新增的 SIMILAR TO操作符、POSIX风格的正则表达式。另外还有一个模式匹配函数 substring 可用,它可以使用 SIMILAR TO 风格或者 POSIX 风格的正则表达式。 .. tip:: 如果你的模式匹配要求比这些还多,请考虑用 Perl 或 Tcl 写一个用户定义函数。 LIKE -------- :: string LIKE pattern [ESCAPE escape-character] string NOT LIKE pattern [ESCAPE escape-character] 每个 **pattern** 定义了一系列字符串。如果该 **string** 包含在pattern 定义的一系列字符串中,LIKE 表达式返回true。(反之亦然,当LIKE 返回true时,NOT LIKE 表达式返回flase。一个等价的表达式是NOT (string LIKE pattern)。) 如果pattern不包含百分号或者下划线,那么该模式只代表它本身; 这时候LIKE的行为就像等号操作符。在pattern 里的下划线(_)匹配任何单个字符;而一个百分号(%) 匹配零或多个任何序列。 一些例子: :: 'abc' LIKE 'abc' true 'abc' LIKE 'a%' true 'abc' LIKE '_b_' true 'abc' LIKE 'c' false LIKE模式匹配总是覆盖整个字符串。因此, 如果想要匹配在字符串内部任何位置的序列,该模式必须以百分号开头和结尾。 要匹配下划线或者百分号本身,在 **pattern** 里相应的字符必须前导转义字符。缺省的转义字符是反斜杠, 但是你可以用ESCAPE子句指定一个。要匹配转义字符本身, 写两个转义字符。 值得注意的是,反斜杠在字符串中有特殊的含义,所以在SQL 声明中写包含一个反斜杠的模式常量必须写两个反斜杠(假设使用了escape string语义)。因此,在模式中匹配一个反斜杠意味着在声明中写四个反斜杠。你可以通过使用ESCAPE 声明一个不同的转义符;然后一个反斜杠对LIKE 将不再特别。(但是它对string 解析器仍是特别的,所以仍需要写两个反斜杠)。 我们也可以通过写成ESCAPE ''的方式关闭转义机制, 这时,我们就不能关闭下划线和百分号的特殊含义。 关键字ILIKE可以用于替换LIKE, 令该匹配就当前的区域设置是大小不敏感的。这个特性不是SQL标准, 是 OushuDB 扩展。 操作符~~等效于LIKE,而~~* 等效于ILIKE。还有!~~和!~~* 操作符分别代表NOT LIKE和NOT ILIKE。 SIMILAR TO 正则表达式 ----------------------- :: string SIMILAR TO pattern [ESCAPE escape-character] string NOT SIMILAR TO pattern [ESCAPE escape-character] SIMILAR TO根据自己的模式是否匹配给定字符串而返回真或者假。 它和LIKE非常类似,只不过它使用 SQL 标准定义的正则表达式理解模式。 SQL 标准的正则表达式是在LIKE 表示法和普通的正则表达式表示法之间奇妙的交叉。 类似LIKE,SIMILAR TO 操作符只有在它的模式匹配整个字符串的时候才能成功; 这一点和普通的正则表达式的行为不同,在普通的正则表达式里, 模式匹配字符串的任意部分。和LIKE类似的地方还有 SIMILAR TO使用\_和% 分别匹配单个字符和任意字符串(这些和 POSIX 正则表达式里的. 和.*兼容)。 除了这些从LIKE借用的功能之外,SIMILAR TO 支持下面这些从 POSIX 正则表达式借用的模式匹配元字符: * \|表示选择(两个候选之一) * \*表示重复前面的项零次或更多次 * +表示重复前面的项一次或更多次 * Parentheses ()把项组合成一个逻辑项 * [...] 声明一个字符类,只在POSIX正则表达式中 值得注意的是不提供有限的重复(? 和{...}),虽然它们在POSIX 可用。而且,点(.)不是一个匹配字符。 和LIKE一样,反斜杠关闭所有这些元字符的特殊含义; 当然我们也可以用ESCAPE声明另外一个转义字符。 一些例子: :: 'abc' SIMILAR TO 'abc' true 'abc' SIMILAR TO 'a' false 'abc' SIMILAR TO '%(b|d)%' true 'abc' SIMILAR TO '(b|c)%' false 带三个参数的substring( **string** from **pattern** for **escape-character** ) 函数提供了一个从字符串中抽取一个匹配 SQL 正则表达式模式的子字符串功能。 和SIMILAR TO一样,声明的模式必须匹配整个字符串, 否则函数失效并返回 NULL 。为了标识在成功的时候应该返回的模式部分, 模式必须出现后跟双引号(")的两个转义字符。 匹配这两个标记之间的模式的字符串将被返回。 一些例子: :: substring('foobar' from '%#"o_b#"%' for '#') oob substring('foobar' from '#"o_b#"%' for '#') NULL POSIX 正则表达式 ----------------- 下表列出了使用POSIX 正则表达式进行模式匹配时可用的操作符。 **表.正则表达式匹配操作符** .. list-table:: :widths: auto :header-rows: 1 * - 操作符 - 描述 - 例子 * - ~ - 匹配正则表达式,大小写敏感 - 'thomas' ~ '.*thomas.*' * - ~* - 匹配正则表达式,大小写不敏感 - 'thomas' ~* '.*Thomas.*' * - !~ - 不匹配正则表达式,大小写敏感 - 'thomas' !~ '.*Thomas.*' * - !~* - 不匹配正则表达式,大小写不敏感 - 'thomas' !~* '.*vadim.*' POSIX正则表达式提供了比LIKE和SIMILAR TO 操作符更强大的模式匹配的方法。许多 Unix 工具,比如egrep, sed,awk使用类似的模式匹配语言。 正则表达式是一个字符序列,它是定义一个字符串集合(一个正则集合 )的缩写。如果一个字符串是正则表达式描述的正则集合中的一员时, 我们就说这个字符串匹配该正则表达式。和LIKE一样, 模式字符准确地匹配字符串字符,除非在正则表达式语言里有特殊字符 (不过正则表达式用的特殊字符和LIKE用的不同)。 和LIKE不一样的是,正则表达式可以匹配字符串里的任何位置, 除非该正则表达式明确地锚定在字符串的开头或者结尾。 一些例子: :: 'abc' ~ 'abc' true 'abc' ~ '^a' true 'abc' ~ '(b|d)' true 'abc' ~ '^(b|c)' false 带两个参数的substring( **string** from **pattern** ) 函数提供了从字符串中抽取一个匹配 POSIX 正则表达式模式的子字符串的方法。 如果没有匹配它返回 NULL ,否则就是文本中匹配模式的那部分。 但是如果该模式包含任何圆括弧,那么将返回匹配第一对子表达式(对应第一个左圆括弧的)的文本。 如果你想在表达式里使用圆括弧而又不想导致这个例外, 那么你可以在整个表达式外边放上一对圆括弧。 一些例子: :: substring('foobar' from 'o.b') oob substring('foobar' from 'o(.)b') o regexp_replace函数提供了将匹配 POSIX 正则表达式模式的子字符串替换为新文本的功能。它的语义为regexp_replace( **source**, **pattern**, **replacement** [, **flags** ]).如果没有匹配 pattern 的子字符串, 那么返回不加修改的source字符串。如果有匹配, 则返回的 source字符串里面的对应子字符串将被 **replacement** 字符串替换掉。**replacement** 字符串可以包含\\n, 这里的n是 1 到 9 ,表明源字符串中匹配第n 个圆括弧子表达式的部分将插入在该位置,并且它可以包含\\& 表示应该插入匹配整个模式的字符串。如果你需要放一个文本反斜杠在替换文本里, 那么写\\ \\。(无论何时,假设转义语义被使用,在写文本常量字符串时,记得写双反斜杠)。可选的 **flags** 参数包含零个或多个改变函数行为的单字母标记。i表示进行大小写无关的匹配, g表示替换每一个匹配的子字符串而不仅仅是第一个。 一些例子: :: regexp_replace('foobarbaz', 'b..', 'X') fooXbaz regexp_replace('foobarbaz', 'b..', 'X', 'g') fooXX regexp_replace('foobarbaz', 'b(..)', E'X\\1Y', 'g') fooXarYXazY OushuDB 的正则表达式通过使用Henry Spencer 写的一个包实现,下面大部分的正则表达式的描述都是逐字地拷贝自他的手册条目。 正则表达式细节 ++++++++++++++++ 正则表达式(REs),在POSIX 1003.2中定义, 它有两种形式:扩展 RE或ERE (基本上就是在egrep里的那些),基本RE 或BRE(基本上就是在ed里的那些)。OushuDB 两种形式都支持,而且还实现了不在POSIX 中的一些拓展,但是由于可用性在类似 Perl 或者 Tcl 这样的语言中得到广泛应用。使用了那些非 POSIX 扩展的正则表达式叫高级RE 或ARE。ARE 几乎完全是 ERE 的超集,但是 BRE 有几个符号上的不兼容(以及更多的限制)。我们首先描述 ARE 和 ERE 形式,描述那些只适用于 ARE 的特性,然后描述与 BRE 的区别是什么。 .. note:: OushuDB 接受的正则表达式的形式可以通过设定regex_flavor 运行时参数来选择。通常的设定是advanced ,但是可能选择extended 为了最大向后兼容性。 一个正则表达式定义为一个或多个分支, 由|分隔。它可以匹配其中任何一个分支。 一个分支是零个或多个有修饰的原子或约束连接而成。 一个原子匹配第一个,后面的原子匹配第二个,以此类推;一个空分支匹配空字符串。 一个有修饰的原子是一个原子,后面可能跟着一个量词。 没有量词的时候,它匹配一个原子,有量词的时候,它可以匹配若干个原子。 原子可以是在下表里面显示的任何可能。 可能的量词和他们的含义在 **表.正则表达式量词** 里显示。 一个约束匹配一个空字符串,但只是在满足特定条件下才匹配。 约束可以在能够使用原子的地方使用,只是它不能跟着量词。 最简单的原子在 **表.正则表达式约束** 里显示;更多的约束稍后描述。 **表.正则表达式原子** .. list-table:: :widths: auto :header-rows: 1 * - 原子 - 描述 * - (re) - (re 是任意正则表达式)匹配一个对re 的匹配,有可报告的匹配信息。 * - (?:re) - 同上,但是匹配不会被报告(一个"非捕获"圆括弧),只在 ARE 中有。 * - \. - 匹配任意单个字符 * - [chars] - 一个方括弧表达式,匹配任意的 **chars** (详见 `方括弧表达式 <./pattern-matching.html#id3>`_ ) * - \\k - (k是非字母数字字符)匹配一个当作普通字符看待的特定字符, 比如\\匹配一个反斜杠。 * - \\c - c是一个字母数字(可能跟着其它字符),它是一个转义, 参阅 `正则表达式转义 <./pattern-matching.html#id8>`_ 。仅存在于 ARE 中;在 ERE 和 BRE 中, 它匹配c。 * - { - 如果后面跟着一个非数字字符,那么就匹配左花括弧{; 如果跟着一个数字,那么它是范围的开始(见下面) * - x - 这里的x是一个没有其它特征的单个字符,则匹配该字符 RE不能以\\结尾。 .. note:: 在 OushuDB 字符串中,反斜杠(\\)已经有了特殊的含义。要写一个包含一个反斜杠的模式常量,你必须在声明中写两个反斜杠,假设转义字符串语义被使用。 **表.正则表达式量词** .. list-table:: :widths: auto :header-rows: 1 * - 量词 - 匹配 * - \* - 一个匹配 0 或者更多个原子的序列 * - \+ - 一个匹配 1 或者更多个原子的序列 * - \? - 一个匹配 0 或者 1个原子的序列 * - \{m} - 一个正好匹配m个原子的序列 * - \{m,} - 一个匹配m个或者更多原子的序列 * - \{m, n} - 一个匹配m到n个(包含两端)原子的序列; m不能比n大 * - \*? - \*的非贪婪模式 * - \+? - \+的非贪婪模式 * - \?? - \?的非贪婪模式 * - \{m}? - \{m}的非贪婪模式 * - \{m,}? - \{m,}的非贪婪模式 * - \{m, n}? - \{m, n}的非贪婪模式 {...}的形式被称作范围。 一个范围内的数字m和n都是无符号十进制整数, 允许的数值从 0 到 255 (闭区间)。 非贪婪的量词(只在 ARE 中可用)匹配对应的正常(贪婪)模式, 区别是它寻找最少的匹配,而不是最多的匹配。参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ 获取细节。 .. note:: 一个量词不能紧跟在另外一个量词后面。 量词不能是表达式或者子表达式的开头,也不能跟在^ 或|后面。 **表.正则表达式限制** .. list-table:: :widths: auto :header-rows: 1 * - 约束 - 描述 * - \^ - 匹配字符串的开头 * - \$ - 匹配字符串的结尾 * - \(?=re) - 正前瞻匹配任何匹配re 的子字符串起始点(只在 ARE 中有) * - \(?!re) - 负前瞻匹配任何不匹配re 的子字符串起始点(只在 ARE 中有) 前瞻约束不能包含后引用(参阅 `正则表达式转义 <./pattern-matching.html#id4>`_ ), 并且在其中的所有圆括弧都被认为是不捕获的。 方括弧表达式 +++++++++++++++ 方括弧表达式是一个包围在[]里的字符列表。 它通常匹配任意单个列表中的字符(又见下文)。如果列表以^开头, 它匹配任意单个(又见下文) **不在** 该列表中的字符。如果该列表中两个字符用 -隔开,那它就是那两个字符(包括在内)之间的所有字符范围的缩写, 比如,在ASCII里[0-9]包含任何十进制数字。 两个范围共享一个终点是非法的,比如a-c-e。这个范围与字符集序列关系密切, 可移植的程序不应该依靠它们。 想在列表中包含文本],可以让它做列表的首字符(如果用到了, 跟在^ 后面)。想在列表中包含文本-, 可以让它做列表的首字符或者末字符,或者一个范围的第二个终点。想在列表中把文本-当做范围的第一个终点,把它用[. 和.]包围起来,这样它就成为一个集合元素(见下文)。 除了这些字符本身,和一些用[的组合(见下段), 以及转义(只在 ARE 中有效)以外,所有其它特殊字符在方括弧表达式里都失去它们的特殊含义。 特别是,在 ERE 和 BRE 规则下\\\不是特殊的,但在 ARE 里, 它是特殊的(还是引入一个转义)。 在一个方括弧表达式里,一个集合元素(一个字符、一个当做一个字符的多字符序列、 或者一个表示上面两种情况的集合序列)包含在[.和.] 里面的时候表示该集合元素的字符序列。该序列是该方括弧列表的一个元素。 在方括弧表达式里,在[=和=] 里包围的集合元素是一个 *等效表* ,代表等于这里所有集合元素的字符序列, 包括它本身(如果没有其它等效集合元素,那么就好像封装元素是[. 和.])。比如,如果o和^ 是一个等效表的成员,那么[[=o=]],[[=^=]], [o^]都是同义的。一个等效表不能是一个范围的端点。 在方括弧表达式里,在[:和:] 里面封装的字符表名字代表属于该表的所有字符的列表。标准的字符表名字是: alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit。 它们代表在ctype 里定义的字符表。本地化设置可能会提供其它的表。字符表不能用做一个范围的端点。 在方括弧表达式里有两个特例:方括弧表达式[[:<:]]和 [[:>:]]是约束,分别匹配一个单词开头和结束的空串。 单词定义为一个单词字符序列,前面和后面都没有其它单词字符。 单词字符是一个alnum字符(和ctype 里定义的一样)或者一个下划线。这是一个扩展,兼容POSIX 1003.2 , 但那里面并没有说明,而且在准备移植到其它系统里去的软件里一定要小心使用。 通常下面描述的约束转义更好些;他们并非更标准,但是更容易输入。 正则表达式转义 +++++++++++++++ 转义是以\\开头,后面跟着一个字母数字字符的特殊序列。 转义有好几种变体:字符项、表缩写、约束转义、后引用。在 ARE 里,如果一个\\ 后面跟着一个字母数字,但是并未组成一个合法的转义,那么它是非法的。在 ERE 里则没有转义: 在方括弧表达式之外,一个跟着字母数字字符的\\只是表示该字符是一个普通的字符, 而在一个方括弧表达式里,\\是一个普通的字符(后者实际上是 ERE 和 ARE 之间的不兼容)。 *字符项转义* 用于方便我们声明正则表达式里那些不可打印的字符。 它们在 **表.正则表达式字符项转义** 里列出。 *类缩写转义* 用来提供一些常用的字符类缩写。 他们在 **表.正则表达式类缩写转义** 里列出。 *约束转义* 是一个约束,如果满足特定的条件,它匹配该空字符串,以转义形式写出。 它们在 **表.正则表达式约束转义** 里列出。 *后引用(\\n)* 匹配数字n 指定的前面的圆括弧子表达式匹配的同一个字符串(参阅 **表.正则表达式后引用** )。比如,([bc])\\1匹配bc但是不匹配bb或cb。 正则表达式里的子表达式必须完全在后引用前面。子表达式以它的括号的顺序排序。 非捕获圆括弧并不定义子表达式。 .. note:: 请注意,如果把模式当作一个 SQL 字符串常量输入,那么转义前导的\\需要双倍地写: :: '123' ~ E'^\\d{3}' true **表.正则表达式字符项转义** .. list-table:: :widths: auto :header-rows: 1 * - 转义 - 描述 * - \\a - 警笛(铃声)字符,和 C 里一样 * - \\b - 退格,和 C 里一样 * - \\B - \的同义词,用于减少反斜杠加倍的需要 * - \\cX - (这里X是任意字符)字符的低 5 位和X 里的相同,其它位都是 0 * - \\e - 集合序列名字是ESC的字符,如果不是, 则是八进制值为 033 的字符 * - \\f - 进纸,和 C 里一样 * - \\n - 换行,和 C 里一样 * - \\r - 回车,和 C 里一样 * - \\t - 水平制表符,和 C 里一样 * - \\uwxyz - (这里的wxyz是恰好四位十六进制位)本机字节序的 UTF-16 字符 U+wxyz * - \\Ustuvwxyz - (这里的stuvwxyz是恰好八位十六进制位) 为假想中的 Unicode 32 位扩展保留的 * - \\v - 垂直制表符,和 C 里一样 * - \\xhhh - (这里的hhh是一个十六进制序列)十六进制值为 0xhhh的字符(不管用了几个十六进制位, 都是一个字符) * - \\0 - 值为0的字符 (null 字节) * - \\xy - (这里的xy是恰好两个八进制位, 并且不是一个后引用)八进制值为0xy 的字符 * - \\xyz - (这里的xyz是恰好三位八进制位, 并且不是一个后引用)八进制值为0xyz 的字符 十六进制位是0-9, a-f, A-F。八进制位是0-7。 字符项转义总是被当作普通字符。比如,\\135是 ASCII 中的], 但\\135并不终止一个方括弧表达式。 **表.正则表达式类缩写转义** .. list-table:: :widths: auto :header-rows: 1 * - 转义 - 描述 * - \\d - [[:digit:]] * - \\s - [[:space:]] * - \\w - [[:alnum:]_](注意包含下划线) * - \\D - [^[:digit:]] * - \\S - [^[:space:]] * - \\W - [^[:alnum:]_](注意包含下划线) 在方括弧表达式中,\\d, \\s 和\\w 会失去它们的外层方括弧,而\\D, \\S, 和\\W 是非法的。(比如[a-c\\d]等效于[a-c[:digit:]]。 同样[a-c\\D]等效于[a-c^[:digit:]]的,是非法的。) **表.正则表达式约束转义** .. list-table:: :widths: auto :header-rows: 1 * - 转义 - 描述 * - \\A - 只匹配字符串开头(参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ 获取它和^区别的信息) * - \\m - 只匹配一个词的开头 * - \\M - 只匹配一个词的结尾 * - \\y - 只匹配一个词的开头或者结尾 * - \\Y - 只匹配那些既不是词的开头也不是词的结尾的点 * - \\Z - 只匹配一个字符串的结尾(参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ 获取它和$区别的信息) 一个词的定义是上面[[:<:]]和[[:>:]]的声明。 在方括弧表达式里,约束转义是非法的。 **表.正则表达式后引用** .. list-table:: :widths: auto :header-rows: 1 * - 转义 - 描述 * - \\m - (这里的m是一个非零十进制位) 一个指向第m个子表达式的后引用 * - \\mnn - (这里的m是一个非零十进制位,nn 是更多的十进制位,并且十进制数值mnn 不能大于到这个位置为止的闭合捕获圆括弧的个数)一个指向第mnn 个子表达式的后引用 .. note:: 在八进制字符项转义和后引用之间有一个继承的歧义存在,这个歧义是通过跟着的启发分析解决的, 像上面描述的那样。前导零总是表示这是一个八进制转义。而单个非零数字, 如果没有跟着任何其它数字,那么总是认为是后引用。 一个多数据位的非零开头的序列也认为是后引用(只要它在合适的子表达式后面, 也就是说,数值在后引用的合法范围内),否则就认为是一个八进制。 正则表达式元语法 ++++++++++++++++++ 除了上面描述的主要语法之外,还有几种特殊形式和杂项语法。 通常RE 的特点由regex_flavor 决定。然而,它可以被一个director prefix 覆盖。如果一个正则表达式以***:开头,那么剩下的正则表达式都被当作 ARE 。如果一个的正则表达式以***=开头,那么剩下的正则表达式被当作一个文本串, 所有的字符都被认为是一个普通字符。 一个 ARE 可以以 *嵌入选项* 开头:一个(?xyz) 序列(这里的xyz是一个或多个字母字符)声明影响剩余正则表达式的选项。这些选项覆盖任何前面判断的选项—它们可以重写正则表达式操作符隐含的大小写敏感性,可用的选项字母在下表显示。 **表.ARE 嵌入选项字母** .. list-table:: :widths: auto :header-rows: 1 * - 选项 - 描述 * - b - RE 剩余的正则表达式是 BRE * - c - 大小写敏感匹配(覆盖操作符类型) * - e - RE 剩余的正则表达式是 ERE * - i - 大小写不敏感匹配(参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ )(覆盖操作符类型) * - m - n的历史同义词 * - n - 新行敏感匹配(参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ ) * - p - 新行敏感匹配(参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ ) * - q - RE 剩余的正则表达式为一个文本("引起")字符串,所有都是普通字符。 * - s - 非新行敏感匹配(缺省) * - t - 紧语法(缺省,见下文) * - w - 反转部分新行敏感("怪异")匹配(参阅 `正则表达式匹配规则 <./pattern-matching.html#id6>`_ ) * - x - 扩展的语法(见下文) 嵌入的选项在终止其序列的)发生作用。他们只在 ARE 的开始处起作用(如果有, 则在任何***:指示器后面)。 除了通常的正则表达式语法(这种情况下所有字符都重要), 还有一种扩展语法,可以通过声明嵌入的x选项获得。 在扩展语法里,正则表达式中的空白字符被忽略,就像那些在# 和新行之间的字符一样(或正则表达式的结尾)。 这样就允许我们给一个复杂的正则表达式分段和注释。不过这个基本规则上有三种例外: * 前置了\\的空白字符或者 #保留 \ * 方括弧里的空白或者#保留 \ * 在多字符符号里面不能出现空白和注释,比如(?: \ 在这里,空白是空格、水平制表符、新行、和任何属于 *space* (空白)字符表的字符。 最后,在 ARE 里,方括弧表达式外面,序列(?#ttt) (这里的ttt是任意不包含)的文本)是一个注释,完全被忽略。 同样,这样的东西是不允许出现在多字符符号的字符中间的,比如(?:。 这样的注释是比有用的机制的更久远的历史造成的,他们的用法已经废弃了; 我们应该使用扩展语法代替他。 如果声明了一个初始化的***=指示器,那么所有这些元语法扩展都 *不能* 使用,因为这样表示把用户输入当作一个文本字符串而不是正则表达式对待。 正则表达式匹配规则 +++++++++++++++++++++ 在正则表达式可以匹配给出的字符串中多于一个子字符串的情况下, 正则表达式匹配字符串中最靠前的那个子字符串。 如果正则表达式可以匹配在那个位置开始的多个子字符串,要么是取最长的子字符串, 要么是最短的,具体哪种,取决于正则表达式是 *贪婪* 的还是 *非贪婪* 的。 一个正则表达式是否贪婪取决于下面规则: * 大多数原子,以及所有约束,都没有贪婪属性(因为它们毕竟无法匹配个数变化的文本)。 * 在一个正则表达式周围加上圆括弧并不会改变其贪婪性。 * 一个带一个固定重复次数的量词({m} 或{m}?) 量化的原子和原子自身有着同样的贪婪性(可能是没有)。 * 一个带其它普通的量词(包括{m,n} 中m等于n的情况)量化的原子是贪婪的(首选最长匹配)。 * 一个带非贪婪量词(包括{m,n}? 中m等于n的情况)量化原子是非贪婪的(首选最短匹配)。 * 一个分支(也就是一个没有顶级|操作符的正则表达式) 和它里面的第一个有贪婪属性的量化原子有着同样的贪婪性。 * 一个由|操作符连接起来的两个或者更多分支组成的正则表达式总是贪婪的。 上面的规则所描述的贪婪属性不仅仅适用于独立的量化原子, 而且也适用于包含量化原子的分支和整个正则表达式。这里的意思是, 匹配是按照分支或者整个正则表达式作为一个整体 匹配最长或者最短的子字符串的可能。一旦整个匹配的长度确定, 那么匹配任意子表达式的部分就基于该子表达式的贪婪属性进行判断, 在正则表达式里面早开始的子表达式的优先级高于晚开始的子表达式。 一个表达这些的例子: :: SELECT SUBSTRING('XY1234Z', 'Y*([0-9]{1,3})'); Result: 123 SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); Result: 1 在第一个例子里,正则表达式作为整体是贪婪的,因为Y*是贪婪的。 它可以匹配从Y开始的东西,并且它匹配从这个位置开始的最长的字符串, 也就是Y123。输出是这里的圆括弧包围的部分,或者说是123。 在第二个例子里,正则表达式总体上是一个非贪婪的正则表达式 ,因为Y*? 是非贪婪的。它可以匹配从Y开始的最短的子字符串,也就是说Y1。 子表达式[0-9]{1,3}是贪婪的,但是它不能修改总体匹配长度的决定; 因此它被迫只匹配1。 简单说,如果一个正则表达式同时包含贪婪和非贪婪的子表达式, 那么总匹配长度要么是最长可能,要么是最短可能,取决于给整个正则表达式赋予的贪婪属性。 给子表达式赋予的贪婪属性只影响在这个匹配里,各个子表达式之间相互允许 "吃进"的多少。 量词{1,1}和{1,1}? 可以分别用于在一个子表达式或者整个正则表达式上强制贪婪或者非贪婪。 匹配长度是以字符衡量的,而不是集合的元素。一个空字符串会被认为比什么都不匹配长。 比如:bb*匹配abbbc的中间三个字符; (week|wee)(night|knights)匹配weeknights的所有十个字符; 而(.*).*匹配abc的时候,圆括弧包围的子表达式匹配所有三个字符; 而如果用(a*)*匹配bc,那么正则表达式和圆括弧子表达式都匹配空字符串。 如果声明了大小写不敏感的匹配,那么效果就好像把所有字母上的大小写区别取消了一样。 如果一个存在大小写差别的字母以一个普通字符的形式出现在方括弧表达式外面, 那么它实际上被转换成一个包含大小写的方括弧表达式,也就是说,x 变成[xX]。如果它出现在一个方括弧表达式里面, 那么它的所有大小写的同族都被加入方括弧表达式中,也就是说,[x] 变成[xX]而[^x]变成 [^xX]。 如果声明了新行敏感匹配,.和使用^ 的方括弧表达式将永远不会匹配新行字符(这样,匹配就绝对不会跨新行, 除非正则表达式明确地安排了这样的情况)并且^和$ 除了分别匹配字符串开头和结尾之外,还将分别匹配新行后面和前面的空字符串。 但是 ARE 转义\\A和\\Z 仍然 *只* 匹配字符串的开头和结尾。 如果声明了部分新行敏感匹配,那么它影响.和方括弧表达式, 这个时候和新行敏感匹配一样,但是不影响^和$。 如果声明了反转部分新行敏感匹配,那么它影响^和$, 作用和新行敏感匹配里一样,但是不影响.和方括弧表达式。 这个没什么太多用途,只是为了对称提供的。 限制和兼容性 ++++++++++++++ 在这个实现里,对正则表达式的长度没有特别的限制,但是, 那些希望能够有很好移植性的程序应该避免写超过 256 字节的正则表达式 , 因为 POSIX 兼容的实现可以拒绝接受这样的正则表达式。 ARE 实际上和 POSIX ERE 不兼容的唯一的特性是在方括弧表达式里\\ 并不失去它特殊的含义。所有其它 ARE 特性都使用在 POSIX ERE 里面是非法或者是未定义、 未声明效果的语法;指示器的***就是在 POSIX 的 BRE 和 ERE 之外的语法。 许多 ARE 扩展都是从 Perl 那里借来的,但是有些做了修改,清理了一下, 以及一些 Perl 里没有出现的扩展。要注意的不兼容包括\\b, \\B, 对结尾的新行缺乏特别的处理,对那些新行敏感匹配的附加的补齐方括弧表达式, 在前瞻约束里对圆括弧和方括弧引用的限制,以及最长/最短匹配(而不是第一匹配)语义。 基本正则表达式 ++++++++++++++++ BRE 在几个方面和 ERE 不太一样。在BRE里,\|, +,? 都是普通字符,它们没有等效的功能替换。范围的分隔符是\\{和\\}, 因为{和}本身是普通字符。嵌套的子表达式的圆括弧是\\( 和\\),因为(和)自身是普通字符。 除非在正则表达式开头或者是圆括弧封装的子表达式开头,^都是普通字符, 除非在正则表达式结尾或者是圆括弧封装的子表达式的结尾,$是一个普通字符, 而如果*出现在正则表达式开头或者是圆括弧封装的子表达式开头 (前面可能有^),那么它是个普通字符。最后,可以用单数字的后引用, 以及\\<和\\>分别是[[:<:]]和[[:>:]] 的同义词;在BRE里没有其它的转义。