21.KES正则表达式支持
21.1.正则表达式语法
21.1.1.POSIX正则表达式
下表列出了所有可用的列表 POSIX 匹配正则表达式模式的操作符。
操作符 |
描述 |
例子 |
---|---|---|
|
匹配正则表达式,大小写敏感 |
|
``~ `` |
匹配正则表达式,大小写不敏感 |
|
|
不匹配正则表达式,大小写敏感 |
|
``!~ `` |
不匹配正则表达式,大小写不敏感 |
|
POSIX正则表达式提供比例LIKE
和SIMILARTO
操作符的含义更强。 Unix 工具,例如egrep
、sed
或awk
使用与我们在这里描述的述的模式匹配语言。
正则表达式是字符序列,定义 (一个正则集)的缩写。 如果一个串是正则表达式描述的正则集中成员,我们会说这个串与正则表达式相匹配。LIKE
同样,除非正则表达语言中有特殊字符,否则模式字符与串字符准确匹配,否则 — 但正则表达式使用的特殊字符和LIKE
用的不同。 和LIKE
不同的模式是,除非正则表达式显式地挂在串的开头或结尾,否则正则表达式允许匹配串中的任何位置。
一些例子:
SELECT 'abc' ~ 'abc'; ?column? ---------- t (1 row) SELECT 'abc' ~ '^a'; ?column? ---------- t (1 row) SELECT 'abc' ~ '(b|d)'; ?column? ---------- t (1 row) SELECT 'abc' ~ '^(b|c)'; ?column? ---------- f (1 row)
POSIX详细描述模
有两个参数substring
函数,即substring(stringfrompattern)
,提供提取匹配 POSIX 子串的正则表达模式。若不匹配其返回空值,则为文本中匹配模式的一部分。 但是,如果该模式包含任何圆括号,则返回匹配第一对子表达式(对应第一个左圆括号) 的文本。如果想在表达式中使用圆括号而不想导致这个例外,可以在整个表达式外放一对圆括号。 如果您需要在想要提取的子表达式之前有一个圆括号,请参阅后面描述的非捕获性圆括号。
一些例子:
SELECT substring('foobar' from 'o.b'); substring ----------- oob (1 row) SELECT substring('foobar' from 'o(.)b'); substring ----------- o (1 row)
regexp_replace
函数提供匹配 POSIX 用新文本取代正则表达模式的子串。 它的语法是regexp_replace
(source
,pattern
,
replacement
[,flags
])。
若不匹配pattern
,然后返回不修改的source
串。 如有匹配,则返回source
串中的匹配子串将被匹配replacement
串替换掉。replacement
串可以包含\
n
, 其中\
n
是 1 到 9, 显示源串中的匹配模式n
个圆括号子表达式的子串应该被插入, 它可以包含\&
这意味着应该插入与整个模式相匹配的子串。如果您需要在替换文本中放置文本形式的反斜线,请写下\\
。flags
参数是包含另一个或更多单字母标志的可选文本串,可以改变函数的行为。i
指定大小写的匹配与标志无关g
指定替换每个匹配的子串,而不仅仅是第一个。支持标志(但不是g
)描述表7-9。
一些例子:
SELECT regexp_replace('foobarbaz', 'b..', 'X'); regexp_replace ---------------- fooXX (1 row) SELECT regexp_replace('foobarbaz', 'b..', 'X', 'g'); regexp_replace ---------------- fooXX (1 row) SELECT regexp_replace('foobarbaz', 'b(..)', 'X\1Y', 'g'); regexp_replace ---------------- fooXarYXazY (1 row) \ ``regexp_match``\ 回到一个文本数组,它包含一个POSIX正则表达模式与字符串首次匹配得到的子串。其语法是\ ``regexp_match``\ ( ``string`` , ``pattern`` [, ``flags`` ])。其语法是\ ``regexp_match``\ ( ``string`` , ``pattern`` [, ``flags`` ])。如果没有匹配,结果是\ ``NULL``\ 。如果你找到一个匹配,\ ``pattern`` \ 不包括含括号的子表达式,结果是一个单一元素的文本数组,包括与整个模式相匹配的子串。如果你找到一个匹配,\ ``pattern`` \ 含有括号的子表达式,结果是文本数组,其中第一个\ ``n`` \ 个元素是与\ ``pattern`` \ 的第\ ``n`` \ 圆括号表达式匹配的子串(不包括非捕获圆括号,详见下文)。\ ``flags`` \ 参数是一个可选的文本字符串,它包含可以改变函数行为的零或多个单字母标志。 一些例子:
SELECT regexp_match('foobarbequebaz', 'bar.*que'); regexp_match -------------- {barbeque} (1 row) SELECT regexp_match('foobarbequebaz', '(bar)(beque)'); regexp_match -------------- {bar,beque} (1 row)
通常只需要整个匹配的子串或子串NULL
如果不匹配,可以这样写
SELECT (regexp_match('foobarbequebaz', 'bar.*que(1); regexp_match -------------- barbeque (1 row)
regexp_matches
函数返回文本数组的集合包含一个POSIX正则表达模式与字符串匹配得到的子串。regexp_match
有相同的语法。如果没有匹配,函数就不会返回行。如果有匹配并给定g
如果有标志,返回一行。如果有,返回一行。N
匹配并给定g
标志,返回N
好的。每个返回线都是一个文本数组,包含整个匹配的子串或匹配pattern
的圆括号子表达式的子串,这和上面对regexp_match
同样的介绍。regexp_matches
接受表7-9 所有显示的标志,加上它返回所有匹配,而不仅仅是第一个匹配g
标志。
一些例子:
SELECT regexp_matches('foo', 'not there'); regexp_matches --------------- (0 rows) SELECT regexp_matches('foobarbequebazilbarfbonk', '(b[^b]+)(b[^b]+)', 'g'); regexp_matches ---------------- {bar,beque} {bazil,barf} (2 rows)
提示
在大部分情况下,regexp_matches()
应该与g
标志一起使用,因为如果只是想要第一个匹配,使用regexp_match()
会更加简单高效。不过,regexp_match()
仅存在于KingbaseES V8.3 版本以及更高的版本中。当在较老的版本中使用时,一种常用的技巧是把regexp_matches()
调用放在子选择中,例如:
SELECT col1, (SELECT regexp_matches(col2, '(bar)(beque)')) FROM tab;
如果有一个匹配,则这个语句会产生一个文本数组,否则返回NULL
,这和regexp_match()
的做法一样。如果没有子选择,这个查询对于没有匹配的表行根本不会产生输出,显然那不是想要的行为。
regexp_split_to_table
把一个 POSIX 正则表达式模式当作一个定界符来分离一个串。它的语法形式是regexp_split_to_table
( string
,
pattern
[,flags
])。如果没有与 pattern
的匹配,该函数返回 string
。如果有至少有一个匹配,对每一个匹配它都返回从上一个匹配的末尾(或者串的开头)到这次匹配开头之间的文本。当没有更多匹配时,它返回从上一次匹配的末尾到串末尾之间的文本。 flags
参数是一个可选的文本串,它包含零个或更多单字母标志,这些标识可以改变该函数的行为。regexp_split_to_table
能支持的标志在表7-9 中描述。
regexp_split_to_array
函数的行为和regexp_split_to_table
相同,不过regexp_split_to_array
会把它的结果以一个text
数组的形式返回。它的语法是regexp_split_to_array
( string
, pattern
[, flags
])。这些参数和regexp_split_to_table
的相同。
一些例子:
SELECT foo FROM regexp_split_to_table('the quick brown fox jumps over the lazy dog', '\s+') AS foo; foo ------- the quick brown fox jumps over the lazy dog (9 rows) SELECT regexp_split_to_array('the quick brown fox jumps over the lazy dog', '\s+'); regexp_split_to_array ----------------------------------------------- {the,quick,brown,fox,jumps,over,the,lazy,dog} (1 row) SELECT foo FROM regexp_split_to_table('the quick brown fox', '\s*') AS foo; foo ----- t h e q u i c k b r o w n f o x (16 rows)
正如上一个例子所示,正则表达式分离函数会忽略零长度的匹配,这种匹配发生在串的开头或结尾或者正好发生在前一个匹配之后。这和正则表达式匹配的严格定义是相悖的,后者由regexp_match
和regexp_matches
实现,但是通常前者是实际中最常用的行为。其他软件系统如Perl也使用相似的定义。
21.1.2. 正则表达式细节
KingbaseES的正则表达式是使用 Henry Spencer 写的一个包来实现的。下面的正则表达式的大部分描述都是从他的手册页中逐字拷贝过来的。
正则表达式(RE),在POSIX 1003.2 中定义, 它有两种形式:扩展的RE或者是ERE(大概地说就是那些在egrep
里的), 基本的RE或者是BRE(大概地说就是那些在ed
里的)。KingbaseES支持两种形式,并且还实现了一些POSIX标准中没有但是在类似 Perl 或者 Tcl 这样的语言中得到广泛应用的一些扩展。使用了那些非POSIX扩展的RE叫高级RE, 或者本文档里说的ARE。ARE 几乎完全是 ERE 的超集,但是 BRE 有几个符号上的不兼容(以及更多的限制)。我们首先描述 ARE 和 ERE 形式, 描述那些只适用于 ARE 的特性,然后描述 BRE 的区别是什么。
注意
KingbaseES初始时总是推测一个正则表达式遵循 ARE 规则。但是,可以通过为 RE 模式预置一个embedded option来选择限制更多的 ERE 或 BRE 规则,如 正则表达式元语法 中所述。这对为期望准确的POSIX 1003.2 规则的应用提供兼容性很有用。
一个正则表达式被定义为一个或更多分支,它们之间被|
分隔。只要能匹配其中一个分支的东西都能匹配正则表达式。
一个分支是一个或多个量化原子或者约束连接而成。一个原子匹配第一个,然后后面的原子匹配第二个, 以此类推;一个空分支匹配空串。
一个量化原子是一个原子,后面可能跟着一个量词。没有量词的时候,它匹配一个原子, 有量词的时候,它可以匹配若干个原子。一个原子可以是在 表 21.1.2 里面显示的任何可能。 可能的量词和它们的含义在 表 21.1.3 里显示。
一个约束匹配一个空串,但只是在满足特定条件下才匹配。 约束可以在能够使用原子的地方使用,只是它不能跟着量词。简单的约束在 表 21.1.4 里显示; 更多的约束稍后描述。
原子 |
描述 |
---|---|
|
(其中re是任何正则表达式) 匹配一个对re的匹配,匹配将为可能的报告被记下 |
|
同上,但是匹配不会为了报告而被记下 (一个“非捕获”圆括号集) (只对 ARE) |
|
匹配任意单个字符 |
|
一个方括号表达式, 匹配 chars 中的任意一个 |
|
(其中 k 是一个非字母数字字符) 匹配一个被当作普通字符看待的特定字符, 例如, |
|
其中c是一个字母数字 (可它字符) 能跟着其,它是一个转义,(仅对 ARE; 在 ERE 和 BRE 中,它匹配c) |
|
如果后面跟着一个字符,而不是数字, 那么就匹 配左花括弧 |
x |
其中x是一 个没有其它意义的单个字符,则匹配该字符 |
RE 不能以反斜线(\
)结尾。
注意
如果你关掉了 standard_conforming_strings ,任何你写在文字串常量中的反斜线都需要被双写。详见 字符串常量 。
量词 |
匹配 |
---|---|
`` `` |
一个由原子的 0 次或更多次匹配组成的序列 |
|
一个由原子的 1 次或更多次匹配组成的序列 |
|
一个由原子的 0 次或 1 次匹配组成的序列 |
|
一个由原子的 正好m次匹配组成的序列 |
|
一个由原子的m次或更多次匹配组成的序列 |
|
一个由原子的从m次到n次(包括)匹配组成的序 列;m不能超过n |
`` ?`` |
`` ``的非贪婪版本 |
|
|
|
|
|
|
|
|
|
|
使用{
...}
的形式被称作范围。一个范围内的数字m和n都是无符号十进制整数,允许的数值从 0 到 255(包含)。
非贪婪的量词(只在 ARE 中可用)匹配对应的正常(贪婪)模式,区别是它寻找最少的匹配,而不是最多的匹配。详见 正则表达式匹配规则 。
注意
一个量词不能紧跟在另外一个量词后面,例如`` \ 是非法的。量词不能作为表达式或者子表达式的开头,也不能跟在\ ``^
或者|
后面。
约束 |
描述 |
---|---|
|
串开头的匹配 |
|
串末尾的匹配 |
|
在匹配re的子串开始的任何点的positivelookahead匹配(只对 ARE) |
|
在匹配re的子串开始的任何点的negativelookahead匹配(只对 ARE) |
|
只要有 一个点上有一个子串匹配re端, positivelookbehind就在这个点上匹配(只对ARE) |
|
只要有 一个点上有一个子串匹配re端, positivelookbehind就在这个点上匹配(只对ARE) |
lookahead 和 lookbehind 约束不能包含 后引用 (参阅 正则表达式转义 ),并且其中的所有圆括号都被认为是非捕获的。
21.1.3. 方括号表达式
方括号表达式是一个包围在[]
中的字符列表。它通常匹配列表中的任意单个字符(但见下文)。 如果列表以^
开头,它匹配任意单个不在该列表参与部分中的字符。如果该列表中两个字符用-
隔开, 那它就是那两个字符(包括在内)之间的所有字符范围的缩写,例如,在ASCII中[0-9]
匹配任何十进制数字。两个范围共享一个端点是非法的,例如,a-c-e
。范围与字符集关系密切, 可移植的程序应该避免依靠它们。
想在列表中包含文本]
,可以让它做列表的首字符(如果使用了^
,需要放在其后)。 想在列表中包含文本-
,可以让它做列表的首字符或者尾字符,或者一个范围的第二个端点。 想在列表中把文本-
当做范围的起点, 把它用[.
和.]
包围起来,这样它就成为一个排序元素(见下文)。 除了这些字符本身、一些用[
的组合(见下段)以及转义(只在 ARE 中有效)以外,所有其它特殊字符 在方括号表达式里都失去它们的特殊含义。特别是,在 ERE 和 BRE 规则下\
不是特殊的, 但在 ARE 里,它是特殊的(引入一个转义)。
在一个方括号表达式里,一个排序元素(一个字符、一个被当做一个单一字符排序的多字符序列或者一个表示上面两种情况的排序序列名称) 包含在[.
和.]
里面的时候表示该排序元素的字符序列。该序列被当做该方括号列表 的一个单一元素。这允许一个包含多字符排序元素的方括号表达式去匹配多于一个字符,例如,如果排序序列包含一个ch
排序元素, 那么 RE [[.ch.]]*c
匹配chchcc
的头五个字符。
注意
KingbaseES当前不支持多字符排序元素。这些信息描述了将来可能有的行为。
在方括号表达式里,包围在[=
和=]
里的排序元素是一个等价类, 代表等效于那一个的所有排序元素的字符序列,包括它本身(如果没有其它等效排序元素,那么就好象封装定界符是[.
和 .]
)。例如,如果o
和^
是一个等价类的成员,那么[[=o=]]
、[[=^=]]
和[o^]
都是同义的。一个等价类不能是一个范围的端点。
在括号表达式中,[:
和 :]
代表所有属于该类的字符列表。 字符类不能用作范围的端点。POSIX标准定义了这些字符类名: alnum
(字母和数字)、 alpha
(字母)、 blank
(空格和制表符)、 cntrl
(控制字符)、digit
(数字的位数)、graph
(除空格外的可打印字符)、 lower
(小写字母)、 print
(可打印字符,包括空格)、 punct
(标点符号)、space
(任何空白), upper
(大写字母)、和 xdigit
(十六进制数字)。 这些标准字符类的行为通常是一致的跨平台为7位ASCII字符集合。是否一个给定的非ASCII字符被认为属于其中一个类,依赖于用于正则表达式函数或运算符的排序规则 (详见 排序规则 ), 或者在默认情况下对数据库的LC_CTYPE
设置(详见 区域支持 )。 即使在名称相似的地区,非ascii字符的分类也可能因平台而异。(但是C
区域设置从不认为任何非ascii字符属于这些类。) 除了这些标准的字符类,KingbaseES定义了ascii
字符类,它包含了准确的7位ASCII集。
方括号表达式里有两个特例:方括号表达式[[:<:]]
和[[:>:]]
是约束, 分别匹配一个单词开头和结束的空串。 单词定义为一个单词字符序列,前面和后面都没有其它 单词字符。单词字符是一个alnum
字符( 和POSIX特性描述中的定义一样) 或者一个下划线。这是一个扩展,兼容POSIX 1003.2, 但那里面并没有说明, 而且在准备移植到其他系统里去的软件里一定要小心使用。通常下文描述 的约束转义更好些(它们并非更标准,但是更容易键入)。
21.1.4. 正则表达式转义
转义是以\
开头,后面跟着一个字母数字字符得特殊序列。 转义有好几种变体:字符项、类缩写、约束转义以及后引用。在 ARE 里, 如果一个\
后面跟着一个字母数字,但是并未组成一个合法的转义, 那么它是非法的。在 ERE 中没有转义:在方括号表达式之外,一个后面跟着字母数字字符的\
只是表示该字符是一个普通的字符,而且在一个方括号表达式里,\
是一个普通的字符(后者实际上在 ERE 和 ARE 不兼容)。
字符项转义用于便于我们在 RE 中声明那些不可打印的或其他习惯的字符。它们显示在 表 21.1.5 中。
类缩写转义用来提供一些常用的字符类缩写。它们显示在 表 21.1.6 中。
约束转义是一个约束,如果满足特定的条件,它匹配该空串。它们显示在 POSIX-CONSTRAINT-ESCAPES-TABLE
中。
后引用(\
n)匹配数字\
n指定的被前面的圆括号子表达式匹配的同一个串 (参阅 表 21.1.7 )。例如,([bc])\1
匹配bb
或者cc
,但是不匹配bc
或者cb
。RE 中子表达式必须完全在后引用前面。子表达式以它们的先导圆括号的顺序编号。非捕获圆括号并不定义子表达式。
转义 |
描述 |
---|---|
|
警告(响铃)字符,和 C 中一样 |
|
退格,和 C 中一样 |
|
反斜线 ( |
|
(其中X是任意字符)低序5位 和X相同的字符,它的其他位都是零 |
|
排序序列名为 |
|
换页,和 C 中一样 |
|
新行,和 C 中一样 |
|
回车,和 C 中一样 |
|
水平制表符,和 C 中一样 |
|
(其中wxyz正好是四个十六进制位 )十六进制值为 |
|
(其中 stuvwxyz正好是八个十六进制位)十 六进制值为 |
|
垂直制表符,和 C 中一样 |
|
(其中hhh是十六进制位的任意序列 )十六进制值为 |
|
值为 |
|
(其中xy正好是两个八进制位,并且不是一个后引 用)八进制值为 |
|
(其中xyz正好是三个八进制位,并且不是一个后引用)八进制值为 |
十六进制位是0
-9
、a
-f
和A
-F
。八进制位是0
-7
。
指定 ASCII 范围(0-127)之外的值的数字字符项转义的含义取决于数据库编码。 当编码是 UTF-8 时,转义值等价于 Unicode 代码点,例如 \u1234
表示字符U+1234
。对于其他多字节编码,字符项转义通常只是指定该字符的字节值的串接。如果该转义值不对应数据库编码中的任何合法字符,将不会发生错误,但是它不会匹配任何数据。
字符项转义总是被当作普通字符。例如,\135
是 ASCII 中的]
, 但\135
并不终止一个方括号表达式。
转义 |
描述 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
在方括号表达式里,\d
、\s
和\w
会失去它们的外层方括号,而\D
、\S
和 \W
是非法的(也就是说,例如[a-c\d]
等效于[a-c[:digit:]]
。同样[a-c\D]
等效于 [a-c^[:digit:]]
的,也是非法的)。
一个词被定义成在上面[[:<:]]
和[[:>:]]
中的声明。在方括号表达式里,约束转义是非法的。
转义 |
描述 |
---|---|
|
(其中m是一 个非零位)一个到第m个子表达式的后引用 |
|
(其中m是一个非零 位,并且nn是一些更多的位,并且十六进制 值mnn不超过目前能看到的封闭捕获圆括号 的数目)一个到第mnn个子表达式的后引用 |
注意
在八进制字符项转义和后引用之间有一个历史继承的歧义存在,这个歧义是 通过下面的启发式规则解决的,像上面描述地那样。前导零总是表示这是一个八进制转义。 而单个非零数字,如果没有跟着任何其它位,那么总是被认为后引用。 一个多位的非零开头的序列也被认为是后引用,只要它出现在合适的子表达式后面 (也就是说,在后引用的合法范围中的数),否则就被认为是一个八进制。
21.1.5. 正则表达式元语法
除了上面描述的主要语法之外,还有几种特殊形式和杂项语法。
如果一个 RE 以`` **:\ 开头,那么剩下的 RE 都被当作 ARE(这在KingbaseES中通常是无效的,因为 RE 被假定为 ARE,但是如果 ERE 或 BRE 模式通过\ ``flags
参数被指定为一个正则表达式函数时,它确实能产生效果)。如果一个 RE 以`` **=``开头, 那么剩下的 RE 被当作一个文本串,所有的字符都被认为是一个普通字符。
一个 ARE 可以以嵌入选项开头:一个序列(?
xyz)
(这里的xyz是一个或多个字母字符)声明影响剩余 RE 的选项。 这些选项覆盖任何前面判断的选项 — 特别地,它们可以覆盖一个正则表达式操作符隐含的大小写敏感的行为,或者覆盖flags参数中的正则表达式函数。可用的选项字母在下表中显示。注意这些同样的选项字母也被用在正则表达式函数的flags参数中。
嵌入选项在)
终止序列时发生作用。它们只在 ARE 的开始处起作用 (在任何可能存在的`` **:``控制器后面)。
除了通常的(紧密的)RE 语法(这种情况下所有字符都有效), 还有一种扩展语法,可以通过声明嵌入的x
选项获得。在扩展语法里,RE 中的空白字符被忽略,就像那些在#
和其后的新行(或 RE 的末尾)之间的字符一样。这样就允许我们给一个复杂的 RE 分段和注释。不过这个基本规则有三种例外:
-
空白字符或前置了
\
的#
将被保留 -
方括号表达式里的空白或者
#
将被保留 -
在多字符符号里面不能出现空白和注释,例如
(?:
为了这个目的,空白是空格、制表符、新行和任何属于 空白
字符类的字符。
最后,在 ARE 里,方括号表达式外面,序列(?#
ttt)
(其中ttt是任意不包含一个)
)的文本)是一个注释, 它被完全忽略。同样,这样的东西是不允许出现在多字符符号的字符中间的,例如 (?:
。这种注释更像是一种历史产物而不是一种有用的设施,并且它们的使用已经被废弃;请使用扩展语法来替代。
如果声明了一个初始的`` **=``控制器,那么所有这些元语法扩展都不能使用,因为这样表示把用户输入当作一个文字串而不是 RE 对待。
21.1.6. 正则表达式匹配规则
在 RE 可以在给定串中匹配多于一个子串的情况下, RE 匹配串中最靠前的那个子串。如果 RE 可以匹配在那个位置开始 的多个子串,要么是取最长的子串,要么是最短的,具体哪种, 取决于 RE 是贪婪的还是非贪婪的。
一个 RE 是否贪婪取决于下面规则:
-
大多数原子以及所有约束,都没有贪婪属性(因为它们毕竟无法匹配个数变化的文本)。
-
在一个 RE 周围加上圆括号并不会改变其贪婪性。
-
带一个固定重复次数量词 (
{
m}
或者{
m}?
) 的量化原子和原子自身具有同样的贪婪性(可能是没有)。 -
一个带其他普通的量词(包括
{
m,
n}
中m等于n的情况)的量化原子是贪婪的(首选最长匹配)。 -
一个带非贪婪量词(包括
{
m,
n}?
中m等于 n的情况)的量化原子是非贪婪的(首选最短匹配)。 -
一个分支 — 也就是说,一个没有顶级
|
操作符的 RE — 和它里面的第一个有贪婪属性的量化原子有着同样的贪婪性。 -
一个由
|
操作符连接起来的两个或者更多分支组成的 RE 总是贪婪的。
上面的规则所描述的贪婪属性不仅仅适用于独立的量化原子,而且也适用于包含量化原子的分支和整个 RE。这里的意思是,匹配是按照分支或者整个 RE 作为一个整体匹配最长或者最短的可能子串。 一旦整个匹配的长度确定,那么匹配任意特定子表达式的部分就基于该子表达式的贪婪属性进行判断,在 RE 里面靠前的子表达式的优先级高于靠后的子表达式。
一个相应的例子:
SELECT SUBSTRING('XY1234Z', 'Y*([0-9]{1,3})'); substring ----------- 123 (1 row) SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); substring ----------- 1 (1 row)
在第一个例子里,RE 作为整体是贪婪的,因为Y ``\ 是贪婪的。它可以匹配从\ ``Y
开始的东西,并且它匹配从这个位置开始的最长的串, 也就是,Y123
。输出是这里的圆括号包围的部分,或者说是123
。在第二个例子里, RE 总体上是一个非贪婪的 RE,因为Y*?
是非贪婪的。它可以匹配从Y
开始的最短的子串,也就是说Y1
。子表达式[0-9]{1,3}
是贪婪的,但是它不能修改总体匹配长度的决定; 因此它被迫只匹配1
。
简而言之,如果一个 RE 同时包含贪婪和非贪婪的子表达式,那么总的匹配长度要么是尽可能长,要么是尽可能短,这取决于给整个 RE 赋予的属性。给子表达式赋予的属性只影响在这个匹配里,各个子表达式之间相互允许“吃掉”的多少。
量词{1,1}
和{1,1}?
可以分别用于在一个子表达式 或者整个 RE 上强制贪婪或者非贪婪。当需要整个 RE 具有不同于从其元素中 推导出的贪婪属性时,这很有用。例如,假设我们尝试将一个包含一些数字的 字符串分隔成数字以及在它们之前和之后的部分,我们可能会尝试这样做:
SELECT regexp_matches('abc01234xyz', '(.*)(\d+)(.*)'); regexp_matches ----------------- {abc0123,4,xyz} (1 row)
这不会有用:第一个. ``\ 是贪婪的,因此它会“吃掉” 尽可能多的字符而留下\ ``\d+
去匹配在最后一个可能位置上的最 后一个数字。我们可能会通过让它变成非贪婪来修复:
SELECT regexp_matches('abc01234xyz', '(.*?)(\d+)(.*)'); regexp_matches ---------------- {abc,0,""} (1 row)
这也不会有用:因为现在 RE 作为整体来说是非贪婪的,因此它会尽快结束 全部的匹配。我们可以通过强制 RE 整体是贪婪的来得到我们想要的:
SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); Result: {abc,01234,xyz}
独立于 RE 的组件的贪婪性之外控制 RE 的整体贪婪性为处理变长模式提供了 很大的灵活性。
在决定更长或者更短的匹配时,匹配长度是以字符衡量的,而不是排序元素。一个空串会被认为比什么都不匹配长。例如:bb ``\ 匹配\ ``abbbc
的中间三个字符;(week|wee)(night|knights)
匹配weeknights
的所有十个字符; 而(.*). ``\ 匹配 ``abc
的时候,圆括号包围的子表达式匹配所有三个字符;当(a*) ``\ 被拿来匹配\ ``bc
时,整个 RE 和圆括号 子表达式都匹配一个空串。
如果声明了大小写无关的匹配,那么效果就好像所有大小写区别在字母表中消失了。如果在多个情况中一个字母以一个普通字符的形式出现在方括号表达式外面,那么它实际上被转换成 一个包含大小写的方括号表达式,也就是说,x 变成 [xX]。 如果它出现在一个方括号表达式里面,那么它的所有大小写的同族都被加入 方括号表达式中,也就是说,x
变成[xX]
。当它出现在一个方括号表达式内时,它的所有大小写副本都被加入到方括号表达式中,例如, [x]
会变成[xX]
,而[^x]
会变成[^xX]
。
如果指定了新行敏感的匹配,.
和使用^
的方括号表达式 将永远不会匹配新行字符(这样,匹配就绝对不会跨越新行,除非 RE 显式地安排了这样的情况)并且^
和$
除了分别匹配串开头和结尾之外,还将分别匹配新行后面和前面的空串。但是 ARE 转义\A
和\Z
仍然只匹配串的开头和结尾。
如果指定了部分新行敏感的匹配,那么它影响.
和方括号表达式, 这个时候和新行敏感的匹配一样,但是不影响^
和$
。
如果指定了逆新行敏感匹配,那么它影响^
和$
,其作用和在新行敏感的匹配里一样,但是不影响.
和方括号表达式。这个并不是很有用,只是为了满足对称性而提供的。
21.2. 正则表达式兼容性与限制
在KingbaseES的ARE正则表达式实现里,对 RE 的长度没有特别的限制。但是,那些希望高移植性的程序应该避免使用长度超过 256 字节的 RE,因为 POSIX 兼容 的实现可以拒绝接受这样的 RE。
21.2.1. ERE兼容性
ARE 实际上和 POSIX ERE 不兼容的唯一的特性是在方括号表达式里\
并不失去它特殊的含义。所有其它 ARE 特性都使用在 POSIX ERE 里面是非法或者是未定义、未声明效果的语法;指示器的`` * ``就是在 POSIX 的 BRE 和 ERE 之外的语法。
KingbaseES V7之前的版本中识别的 ARE 和 ERE 语法存在两个非常明显的不兼容:
-
在 ARE 中,后面跟着一个字母数字字符的
\
要么是一个转义要么是一个错误, 但是在以前的版本里,它只是写该字母数字字符的另外一种方法。这个应该不是什么问题, 因为在以前的版本里没有什么理由会让我们写这样的序列。 -
在 ARE 里,
\
在[]
里还是一个特殊字符, 因此在方括号表达式里的一个文本\
必须被写成\\
。
21.2.2. BRE兼容性
BRE 在几个方面和 ERE 不太一样。在 BRE 中,|
、+
和?
都是普通字符并且没有与它们功能等价的东西。范围的定界符是\{
和\}
, 因为 {
和}
本身是普通字符。嵌套的子表达式的圆括号是\(
和\)
,因为(
和)
自身是普通字符。除非在 RE 开头或者是圆括号子表达式开头,^
都是一个普通字符。 除非在 RE 结尾或者是圆括号子表达式的结尾,$
是一个普通字符。如果`` \ 出现在 RE 开头或者是圆括号封装的子表达式开头 (前面可能有\ ``^
),那么它是个普通字符。最后,可以用单数字的后引用,\<
和\>
分别是[[:<:]]
和[[:>:]]
的同义词;在 BRE 中没有其它可用的转义。
21.2.3. Perl正则表达式兼容性
许多 ARE 扩展都是从 Perl 那里借来的(但是有些被做了修改来清理它们),以及一些 Perl 里没有出现的扩展。要注意的不兼容性包括\b
、\B
、对结尾的新行缺乏特别的处理、对那些被新行敏感匹配的东西附加的补齐方括号表达式、在 lookahead/lookbehind 约束里对圆括号和后引用的限制以及最长/最短 匹配(而不是第一匹配)的语义。