9.7. 模式匹配

PostgreSQL 提供了三种单独的模式匹配方法:传统的 SQL LIKE运算符,最新的SIMILAR TO运算符(在 SQL:1999 中添加)和 POSIX 样式的正则表达式。除了基本的“此字符串是否与该模式匹配?”之外。运算符,函数可用于提取或替换匹配的子字符串并在匹配的位置拆分字符串。

Tip

如果您有超出此范围的模式匹配需求,请考虑使用 Perl 或 Tcl 编写用户定义的函数。

Caution

尽管大多数正则表达式搜索可以很快地执行,但是可以构造正则表达式,这需要花费任意时间和内存。警惕从敌对来源接受正则表达式搜索模式。如果必须这样做,建议强加语句超时。

使用SIMILAR TO模式进行的搜索具有相同的安全隐患,因为SIMILAR TO提供了许多与 POSIX 样式正则表达式相同的功能。

LIKE搜索要比其他两个选项简单得多,可以与可能存在敌意的模式源一起使用。

9.7.1. LIKE

string LIKE pattern [ESCAPE escape-character]
string NOT LIKE pattern [ESCAPE escape-character]

如果* string 与提供的 pattern *相匹配,则LIKE表达式返回 true。 (按预期,如果LIKE返回 true,则NOT LIKE表达式返回 false,反之亦然.等效表达式是NOT (string LIKE pattern).)

如果* pattern *不包含百分号或下划线,则该模式仅表示字符串本身;否则,该模式仅表示字符串本身。在这种情况下,LIKE的行为类似于 equals 运算符。 * pattern *中的下划线(_)表示(匹配)任何单个字符;百分号(%)与零个或多个字符的任何序列匹配。

Some examples:

'abc' LIKE 'abc'    true
'abc' LIKE 'a%'     true
'abc' LIKE '_b_'    true
'abc' LIKE 'c'      false

LIKE模式匹配始终覆盖整个字符串。因此,如果希望匹配字符串中任意位置的序列,则该模式必须以百分号开头和结尾。

要匹配 Literals 下划线或百分号而不匹配其他字符,* pattern *中的相应字符必须在转义字符之后。默认的转义字符是反斜杠,但是可以使用ESCAPE子句选择其他反斜杠。要匹配转义字符本身,请写两个转义字符。

Note

如果您关闭了standard_conforming_strings,则用 Literals 字符串常量编写的任何反斜杠都需要加倍。有关更多信息,请参见Section 4.1.2.1

也可以通过写入ESCAPE ''来选择任何转义字符。这有效地禁用了转义机制,这使得无法关闭模式中下划线和百分号的特殊含义。

根据活动的语言环境,可以使用关键字ILIKE代替LIKE来使匹配不区分大小写。这不是 SQL 标准,而是 PostgreSQL 扩展。

运算符~~等效于LIKE,而~~*对应于ILIKE。还有!~~!~~*运算符分别代表NOT LIKENOT ILIKE。所有这些运算符都是特定于 PostgreSQL 的。您可能会在EXPLAIN输出和类似的位置看到这些运算符名称,因为解析器实际上翻译了LIKE等。这些运算符。

短语LIKEILIKENOT LIKENOT ILIKE在 PostgreSQL 语法中通常被视为运算符;例如,它们可以在* expression * * operator * ANY(* subquery *)结构中使用,尽管ESCAPE子句不能包含在其中。在某些晦涩的情况下,可能有必要改用底层的运算符名称。

还有前缀运算符^@和相应的starts_with函数,涵盖了仅需要按字符串开头进行搜索的情况。

9 .7.2. 与正则表达式相似

string SIMILAR TO pattern [ESCAPE escape-character]
string NOT SIMILAR TO pattern [ESCAPE escape-character]

SIMILAR TO运算符根据其模式是否与给定的字符串匹配而返回 true 或 false。它类似于LIKE,除了它使用 SQL 标准的正则表达式定义来解释模式。 SQL 正则表达式是LIKE表示法和通用正则表达式表示法之间的一个奇怪的交叉。

LIKE一样,SIMILAR TO运算符仅在其模式与整个字符串匹配时才成功;这与常见的正则表达式行为不同,在常规行为中,模式可以匹配字符串的任何部分。与LIKE一样,SIMILAR TO使用_%作为通配符,分别表示任何单个字符和任何字符串(在 POSIX 正则表达式中,它们分别与..*相类似)。

除了从LIKE借用的这些功能之外,SIMILAR TO还支持从 POSIX 正则表达式借用的这些模式匹配元字符:

  • |表示交替(两种选择之一)。

  • *表示重复上一个项目零次或多次。

  • +表示重复前一个项目一次或多次。

  • ?表示重复上一个项目零或一次。

  • { * m * }表示前一项正好重复_m *次。

  • { * m * ,}表示重复上一项* m *或更多次。

  • { * m * , * n * }表示前一项重复至少* m 但不超过 n *次。

  • 括号()可用于将项目分组为单个逻辑项目。

  • 与 POSIX 正则表达式一样,方括号表达式[...]指定字符类。

请注意,句点(.)不是SIMILAR TO的元字符。

LIKE一样,反斜杠会禁用任何这些元字符的特殊含义;或可以使用ESCAPE指定其他转义字符。

Some examples:

'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)substring函数提供了与 SQL 正则表达式模式匹配的子字符串的提取。与SIMILAR TO一样,指定的模式必须与整个数据字符串匹配,否则函数将失败并返回 null。为了指示成功时应返回的模式部分,该模式必须包含两次出现的转义字符,后跟双引号(")。返回与这些标记之间的图案部分匹配的文本。

一些示例,其中#"分隔返回字符串:

substring('foobar' from '%#"o_b#"%' for '#')   oob
substring('foobar' from '#"o_b#"%' for '#')    NULL

9 .7.3. POSIX 正则表达式

Table 9.14列出了使用 POSIX 正则表达式进行模式匹配的可用运算符。

表 9.14. 正则表达式匹配运算符

OperatorDescriptionExample
~匹配正则表达式,区分大小写'thomas' ~ '.*thomas.*'
~*匹配正则表达式,不区分大小写'thomas' ~* '.*Thomas.*'
!~与正则表达式不匹配,区分大小写'thomas' !~ '.*Thomas.*'
!~*与正则表达式不匹配,不区分大小写'thomas' !~* '.*vadim.*'

POSIX 正则表达式提供了比LIKESIMILAR TO运算符更强大的模式匹配方式。诸如egrepsedawk之类的许多 Unix 工具都使用一种模式匹配语言,该语言与此处描述的语言类似。

正则表达式是一个字符序列,是一组字符串(* regular set *)的缩写定义。如果字符串是正则表达式描述的正则集的成员,则认为该字符串与正则表达式匹配。与LIKE一样,模式字符完全匹配字符串字符,除非它们是正则表达式语言中的特殊字符-但是正则表达式与LIKE使用的特殊字符不同。与LIKE模式不同,除非将正则表达式显式锚定到字符串的开头或结尾,否则允许在字符串中的任何位置匹配正则表达式。

Some examples:

'abc' ~ 'abc'    true
'abc' ~ '^a'     true
'abc' ~ '(b|d)'  true
'abc' ~ '^(b|c)' false

POSIX 模式语言将在下面更详细地描述。

具有两个参数substring(string from pattern)substring函数提供与 POSIX 正则表达式模式匹配的子字符串的提取。如果不匹配,则返回 null,否则返回与模式匹配的文本部分。但是,如果该模式包含任何括号,则将返回与第一个带括号的子表达式(左括号在前的那个)匹配的文本部分。如果要在整个表达式中使用括号而不触发此异常,则可以在整个表达式中加上括号。如果在要提取的子表达式之前需要模式中的括号,请参见下面介绍的非捕获括号。

Some examples:

substring('foobar' from 'o.b')     oob
substring('foobar' from 'o(.)b')   o

regexp_replace函数用新文本替换与 POSIX 正则表达式模式匹配的子字符串。它的语法为regexp_replace(* source pattern replacement * [,* +162+ *])。如果pattern *不匹配,则source 字符串不变。如果存在匹配项,则返回 source 字符串,并用 replacement *字符串替换匹配的子字符串。 * replacement *字符串可以包含\ * n ,其中 n 是 1 到 9,表示应该插入与该模式的 n *括号内的子表达式匹配的源子字符串,并且可以包含\&来指示应该插入与整个模式匹配的子字符串。如果需要在替换文本中加上反斜杠 Literals,请 Importing\\。 * flags *参数是一个可选的文本字符串,其中包含零个或多个更改功能行为的单字母标志。标志i指定不区分大小写的匹配,而标志g指定替换每个匹配的子字符串,而不是仅替换第一个。 Table 9.22中描述了受支持的标志(尽管不是g)。

Some examples:

regexp_replace('foobarbaz', 'b..', 'X')
                                   fooXbaz
regexp_replace('foobarbaz', 'b..', 'X', 'g')
                                   fooXX
regexp_replace('foobarbaz', 'b(..)', 'X\1Y', 'g')
                                   fooXarYXazY

regexp_match函数返回捕获的子字符串的文本数组,该字符串是 POSIX 正则表达式模式与字符串的第一次匹配产生的。它的语法为regexp_match(* string pattern * [,* +186+ *])。如果不匹配,则结果为NULL。如果找到匹配项,并且* pattern 不包含带括号的子表达式,则结果是一个单元素文本数组,其中包含与整个模式匹配的子字符串。如果找到匹配项,并且 pattern 包含带括号的子表达式,则结果是一个文本数组,其 n 'th 元素是与 pattern n '带括号的子表达式匹配的子字符串(不计入“非捕获”括号;有关详情,请参见下文. flags *参数是一个可选的文本字符串,包含零个或多个更改功能行为的单字母标志.Table 9.22中描述了受支持的标志。

Some examples:

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接受Table 9.22中显示的所有标志,再加上g标志,该标志命令它返回所有匹配项,而不仅仅是第一个匹配项。

Some examples:

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)

Tip

在大多数情况下,应该将regexp_matches()g标志一起使用,因为如果您只想要第一个匹配项,则使用regexp_match()会更轻松,更高效。但是,regexp_match()仅存在于 PostgreSQL 10 及更高版本中。在旧版本中工作时,一个常见的技巧是在子选择中放置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 * [,* +229+ *])。如果与* pattern 不匹配,则函数返回 string *。如果至少有一个匹配项,则对于每个匹配项,它将返回从最后一个匹配项的末尾(或字符串的开头)到匹配项开始的文本。如果没有更多的匹配项,它将返回从最后一个匹配项的末尾到字符串末尾的文本。 * flags *参数是一个可选的文本字符串,包含零个或多个更改功能行为的单字母标志。 regexp_split_to_table支持Table 9.22中描述的标志。

regexp_split_to_array函数的行为与regexp_split_to_table相同,除了regexp_split_to_array返回其结果为text数组。它的语法为regexp_split_to_array(* string pattern * [,* +243+ *])。参数与regexp_split_to_table相同。

Some examples:

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_matchregexp_matches实现的 regexp 匹配的严格定义相反,但实际上通常是最方便的行为。其他软件系统(例如 Perl)也使用类似的定义。

9 .7.3.1. 正则表达式详细信息

PostgreSQL 的正则表达式是使用 Henry Spencer 编写的软件包来实现的。下面对正则表达式的许多描述都是从他的手册中逐字复制的。

POSIX 1003.2 中定义的正则表达式(RE)有两种形式:扩展 RE 或 ERE(大致为egrep)和* basic * RE 或 BRE(大致为ed)。 PostgreSQL 支持这两种形式,还实现了一些不在 POSIX 标准中的扩展,但是由于它们在诸如 Perl 和 Tcl 之类的编程语言中的可用性而被广泛使用。使用这些非 POSIXextensions 的 RE 在本文档中称为高级 RE 或 ARE。 ARE 几乎是 ERE 的确切超集,但 BRE 具有几种符号上的不兼容性(并且还有很多局限性)。我们首先描述 ARE 和 ERE 表格,并指出仅适用于 ARE 的功能,然后描述 BRE 的不同之处。

Note

PostgreSQL 最初总是假定正则表达式遵循 ARE 规则。但是,可以通过在 RE 模式之前添加“嵌入式选项”来选择更有限的 ERE 或 BRE 规则,如Section 9.7.3.4中所述。这对于与完全期望 POSIX 1003.2 规则的应用程序兼容可能很有用。

正则表达式定义为一个或多个“分支”,以|分隔。它匹配任何与分支之一匹配的东西。

分支是零个或多个串联的“量化的原子”或“约束”。它匹配第一个匹配项,然后匹配第二个匹配项,依此类推;空分支匹配空字符串。

量化的原子是一个* atom ,然后可能是一个 quantifier *。没有量词,它将匹配原子的匹配项。使用量词,它可以匹配原子的一些匹配项。 * atom *可以是Table 9.15中显示的任何可能性。可能的量词及其含义如Table 9.16所示。

  • constraint *匹配一个空字符串,但仅在满足特定条件时才匹配。可以在可以使用原子的情况下使用约束,但不能在其后跟随量词。简单的约束显示在Table 9.17中;稍后将描述更多约束。

表 9.15. 正则表达式原子

AtomDescription
( re )(其中* re 是任何正则表达式)匹配 re *的匹配项,并为可能的报告记录了该匹配项
(?: re )如上,但未在报告中注明匹配项(一组“非捕获”括号)(仅适用于 ARE)
.匹配任何单个字符
[ chars ]一个括号表达式,与* chars *中的任何一个匹配(有关更多详细信息,请参见Section 9.7.3.2)
\ k(其中* k *是非字母数字字符)匹配该字符作为普通字符,例如\\匹配反斜杠字符
\ c其中* c 是字母数字(可能后面跟其他字符)是 escape ,请参见Section 9.7.3.3(仅用于 ARE;在 ERE 和 BRE 中,此匹配 c *)
{当后面跟数字以外的其他字符时,匹配左括号字符{;当后面跟一个数字时,它是* bound *的开头(请参见下文)
x其中* x *是没有其他意义的单个字符,与该字符匹配

RE 不能以反斜杠(\)结尾。

Note

如果您关闭了standard_conforming_strings,则用 Literals 字符串常量编写的任何反斜杠都需要加倍。有关更多信息,请参见Section 4.1.2.1

表 9.16. 正则表达式量词

QuantifierMatches
*原子的 0 个或多个匹配项的序列
+原子的 1 个或多个匹配项的序列
?原子的 0 或 1 个匹配项的序列
{ m }原子的完全* m *匹配的序列
{ m ,}* m *个或更多个原子匹配的序列
{ m , n }原子的* m n *(含)匹配的序列; * m 不能超过 n *
*?*的非贪婪版本
+?+的非贪婪版本
???的非贪婪版本
{ m }?{ * m * }的非贪婪版本
{ m ,}?{ * m * ,}的非贪婪版本
{ m , n }?{ * m * , * n * }的非贪婪版本

使用{ * ... * }的表单称为* bounds 。范围内的数字 m n *是无符号十进制整数,允许的值介于 0 到 255 之间(含 0 和 255)。

非贪婪量词(仅在 ARE 中可用)与它们对应的正常(* greedy *)对应物匹配相同的可能性,但更喜欢匹配次数最小而不是最大的匹配项。有关更多详细信息,请参见Section 9.7.3.5

Note

量词不能立即跟在另一个量词之后,例如**无效。量词不能开始表达式或子表达式,也不能跟随^|

表 9.17. 正则表达式约束

ConstraintDescription
^匹配字符串的开头
$在字符串末尾匹配
(?= re )正向超前在匹配* re *的子字符串开始的任何点匹配(仅适用于 ARE)
(?! re )在所有子串都不匹配的情况下,“ 负前瞻”匹配 re *开始(仅适用于 ARE)
(?<= re )正向后看在匹配* re *的子字符串结束的任何点匹配(仅适用于 ARE)
(?<! re )负向后查找在没有子串匹配* re *结束的任何点匹配(仅适用于 ARE)

前向约束和后向约束不能包含后向引用(请参阅Section 9.7.3.3),并且其中的所有括号都被视为不捕获。

9 .7.3.2. 括号表达式

括号表达式[]内的字符列表。它通常与列表中的任何单个字符匹配(但请参见下文)。如果列表以^开头,则匹配列表其余部分中的任何单个字符* not *。如果列表中的两个字符用-分隔,则这是整理序列中这两个字符之间(包括两个字符)的完整字符的缩写,例如 ASCII 中的[0-9]匹配任何十进制数字。两个范围共享一个端点(例如a-c-e)是非法的。范围与排序 Sequences 非常相关,因此可移植程序应避免依赖它们。

要在列表中包括 Literals],请使其成为第一个字符(如果使用了^之后)。要包含 Literals-,请将其设为第一个或最后一个字符,或范围的第二个端点。要将 Literals-用作范围的第一个端点,请将其用[..]括起来以使其成为整理元素(请参见下文)。除了这些字符,使用[的某些组合(请参阅下一部分)和转义符(仅用于 ARE)之外,所有其他特殊字符在方括号表达式中都失去其特殊意义。特别是,\在遵循 ERE 或 BRE 规则时并不特殊,尽管它在 ARE 中很特殊(因为引入了转义)。

在方括号表达式中,包含在[..]中的归类元素(一个字符,一个像一个字符一样进行归类的多字符序列或任一归类序列名称)代表该归类的字符序列元件。该序列被视为方括号表达式列表的单个元素。这允许包含多字符归类元素的方括号表达式匹配多个字符,例如,如果归类序列包含ch归类元素,则 RE [[.ch.]]*cchchcc的前五个字符匹配。

Note

PostgreSQL 当前不支持多字符整理元素。此信息描述了将来可能发生的行为。

在方括号表达式中,包含在[==]中的排序规则元素是* equivalence class *,表示等于该排序规则的所有排序规则元素(包括其自身)的字符序列。 (如果没有其他等效的整理元素,则将其视为[..]包围.)例如,如果o^是等效类的成员,则[[=o=]][[=^=]][o^]都是同义词。等价类不能是范围的终结点。

在方括号表达式中,用[::]括起来的字符类的名称代表该类所有字符的列表。标准字符类名称是:alnumalphablankcntrldigitgraphlowerprintpunctspaceupperxdigit。这些代表 ctype 中定义的字符类。语言环境可以提供其他语言。字符类不能用作范围的端点。

方括号表达式有两种特殊情况:方括号表达式[[:<:]][[:>:]]是约束,分别匹配单词开头和结尾的空字符串。单词被定义为单词字符序列,该序列既不能在单词字符之前也不能在单词字符之后。Literals 字符是alnum字符(由 ctype 定义)或下划线。这是一个扩展,与 POSIX 1003.2 兼容,但未指定该扩展,在打算移植到其他系统的软件中应谨慎使用。通常最好使用下面描述的约束转义;它们不再是标准的,但更易于键入。

9 .7.3.3. 正则表达式转义

转义是特殊序列,以\开头,后跟字母数字字符。转义符有多种类型:字符 Importing,类速记,约束转义符和反向引用。在 ARE 中,一个\后跟一个字母数字字符但不构成有效的转义符是非法的。在 ERE 中,没有转义符:在括号表达式之外,\后跟字母数字字符仅表示该字符为普通字符,而在括号表达式中\是普通字符。 (后者是 ERE 和 ARE 之间的一种实际不兼容.)

使用字符 Importing 转义符,可以更轻松地在 RE 中指定非打印字符和其他不方便使用的字符。它们显示在Table 9.18中。

类速记转义符为某些常用字符类提供速记。它们显示在Table 9.19中。

约束转义是一个约束,如果满足特定条件,则匹配空字符串,写为转义。它们显示在Table 9.20中。

后向引用(\ * n )与由数字 n *指定的先前带括号的子表达式匹配的相同字符串(请参见Table 9.21)。例如,([bc])\1bbcc匹配,但与bccb不匹配。子表达式必须完全在 RE 中的反向引用之前。子表达式按其前导括号的 Sequences 编号。非捕获括号不定义子表达式。

表 9.18. 正则表达式字符 Importing 转义符

EscapeDescription
\a警觉(响铃)字符,如 C
\b退格键,如 C
\B反斜杠(\)的同义词,以帮助减少反斜杠加倍的需求
\c X(其中* X 是任意字符)低位 5 位与 X *的低位相同,而其他位全为零的字符
\e排序 Sequences 名称为ESC或失败的字符,八进制值033的字符
\f换页,如 C
\n换行符,如 C
\r回车,如 C
\t水平制表符,如 C
\u wxyz(其中* wxyz *正好是四个十六进制数字)十六进制值为0x * wxyz *的字符
\U stuvwxyz(其中* stuvwxyz *正好是八个十六进制数字)十六进制值为0x * stuvwxyz *的字符
\v垂直制表符,如 C
\x hhh(其中* hhh *是十六进制数字的任意序列)十六进制值为0x * hhh *的字符(无论使用多少个十六进制数字,一个字符)
\0值为0的字符(空字节)
\ xy(其中* xy 恰好是两个八进制数字,并且不是反向引用*)八进制值为0 * xy *的字符
\ xyz(其中* xyz 恰好是三个八进制数字,并且不是反向引用*)八进制值为0 * xyz *的字符

十六进制数字是0-9a-fA-F。八进制数字是0-7

数字字符 Importing 转义符指定的 ASCII 范围(0-127)之外的值具有取决于数据库编码的含义。当编码为 UTF-8 时,转义值等效于 Unicode 代码点,例如\u1234表示字符U+1234。对于其他多字节编码,字符 Importing 转义符通常仅指定字符的字节值的串联。如果转义值与数据库编码中的任何合法字符都不对应,则不会引发任何错误,但它将永远不会与任何数据匹配。

字符 Importing 转义符始终被视为普通字符。例如,\135是 ASCII 的],但是\135不会终止括号表达式。

表 9.19. 正则表达式类-速记转义

EscapeDescription
\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^[:digit:]][a-c\D]是非法的.)

表 9.20. 正则表达式约束转义

EscapeDescription
\A仅在字符串的开头匹配(请参见Section 9.7.3.5以了解与^的区别)
\m仅在单词开头匹配
\M仅在单词结尾处匹配
\y仅在单词的开头或结尾匹配
\Y仅在不是单词开头或结尾的点上匹配
\Z仅在字符串末尾匹配(请参见Section 9.7.3.5以了解与$的区别)

如上面的[[:<:]][[:>:]]规范中定义的单词。在方括号表达式中,约束转义是非法的。

表 9.21. 正则表达式回引用

EscapeDescription
\ m(其中* m 是一个非零数字)对第 m *个子表达式的反向引用
\ mnn(其中* m 是非零数字, nn 是更多数字,并且十进制值 mnn 不大于到目前为止所看到的结束捕获括号的数量)对 mnn *'th 的反向引用子表达

Note

八进制字符 Importing 转义和反向引用之间存在固有的歧义,如上所暗示,可以通过以下启发式方法解决。前导零始终表示八进制转义。始终将单个非零数字(而不是另一个数字)作为后向引用。如果不是以零开头的多位数字序列在适当的子表达式之后出现(即,该数字在反向参考的合法范围内),则将其作为反向参考,否则将其视为八进制。

9 .7.3.4. 正则表达元语法

除了上述主要语法外,还有一些特殊形式和其他语法功能。

RE 可以以两个特殊* director 前缀之一开头。如果 RE 以***:开头,则其余 RE 被视为 ARE。 (由于假定 RE 是 ARE,因此在 PostgreSQL 中通常无效;但是,如果正则表达式函数的 flags *参数指定了 ERE 或 BRE 模式,则它确实会起作用.)如果 RE 以***=开头, RE 的其余部分视为 Literals 字符串,所有字符均视为普通字符。

ARE 可以以嵌入选项开头:序列(? * xyz * )(其中* xyz *是一个或多个字母字符)指定影响其余 RE 的选项。这些选项将覆盖所有先前确定的选项-特别是,它们可以覆盖正则表达式运算符或正则表达式函数的flags 参数所暗示的区分大小写的行为。可用的选项字母显示在Table 9.22中。请注意,正则表达式函数的 flags *参数中使用了相同的选项字母。

表 9.22. ARE 嵌入式期权信

OptionDescription
bRE 的其余部分是 BRE
c区分大小写的匹配(覆盖运算符类型)
e其余的 RE 是 ERE
i不区分大小写的匹配(请参阅Section 9.7.3.5)(覆盖运算符类型)
mn的历史同义词
n换行敏感匹配(请参阅Section 9.7.3.5)
p部分对换行符敏感的匹配(请参阅Section 9.7.3.5)
qRE 的其余部分是 Literals(“引用”)字符串,所有普通字符
s非换行敏感匹配(默认)
t严格语法(默认;请参见下文)
w局部不匹配换行符(“怪异”)的逆匹配(请参阅Section 9.7.3.5)
x扩展语法(见下文)

嵌入式选项在)终止序列时生效。它们只能出现在 ARE 的开头(在***:导演之后(如果有)之后)。

除了通常的(* tight )RE 语法(其中所有字符都有效)之外,还有一种 expanded *语法,可通过指定嵌入式x选项来使用。在扩展语法中,将忽略 RE 中的空格字符,以及#和以下换行符(或 RE 的末尾)之间的所有字符。这允许对复杂的 RE 进行段落和 Comments。该基本规则有三个 exception:

  • 保留空格字符或#前面加\

  • 保留括号表达式中的空格或#

  • 空格和 Comments 不能出现在多字符符号中,例如(?:

为此,空格字符为空白,制表符,换行符以及属于* space *字符类的任何字符。

最后,在 ARE 中,在方括号表达式之外,序列(?# * ttt * )(其中* ttt *是不包含)的任何文本)是 Comments,完全被忽略。同样,在多个字符符号的字符之间(例如(?:),不允许这样做。这些 Comment 更多是历史性的产物,而不是有用的工具,因此不建议使用它们。请改用扩展语法。

如果最初的***=主管已指定将用户的 Importing 视为 Literals 字符串而不是 RE,则这些 metas 语法扩展中的*都不可用。

9 .7.3.5. 正则表达式匹配规则

如果 RE 可以匹配给定字符串的多个子字符串,则 RE 匹配字符串中最早的一个子字符串。如果从该点开始 RE 可以匹配多个子字符串,则将根据 RE 是* greedy 还是 non-greedy *来选择最长匹配或最短匹配。

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})');
Result: 123
SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
Result: 1

在第一种情况下,RE 整体上是贪婪的,因为Y*是贪婪的。它可以从Y开始匹配,并且与从_开始的最长字符串匹配。输出是该内容的括号部分,或123。在第二种情况下,RE 整体上是非贪婪的,因为Y*?是非贪婪的。它可以从Y开始匹配,并且与从那里开始的最短字符串匹配,即Y1。子表达式[0-9]{1,3}是贪婪的,但是它不能更改关于总匹配长度的决定;因此它只能匹配1

简而言之,当一个 RE 同时包含贪婪和非贪婪子表达式时,根据分配给整个 RE 的属性,总匹配长度应尽可能长或尽可能短。分配给子表达式的属性仅影响允许它们相对于彼此“吃掉”的匹配数量。

量词{1,1}{1,1}?可分别用于在子表达式或整个 RE 上强制使用贪婪或不贪婪。当您需要整个 RE 具有不同于从其元素推断出的贪婪属性时,这很有用。例如,假设我们试图将包含一些数字的字符串分成数字以及数字前后的部分。我们可以尝试这样做:

SELECT regexp_match('abc01234xyz', '(.*)(\d+)(.*)');
Result: {abc0123,4,xyz}

那没用:第一个.*是贪婪的,因此它会尽可能多地“吃”,而使\d+匹配到最后一个可能的位置,即最后一个数字。我们可以尝试通过使其不贪心来解决此问题:

SELECT regexp_match('abc01234xyz', '(.*?)(\d+)(.*)');
Result: {abc,0,""}

这也不起作用,因为现在 RE 整体上是非贪婪的,因此它将尽快结束整个 match。通过强制整个 RE 贪婪,我们可以得到想要的东西:

SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
Result: {abc,01234,xyz}

与组件的贪婪度分开控制 RE 的整体贪婪度,可以在处理可变长度模式时具有极大的灵 Active。

在确定什么是更长或更短的匹配时,匹配长度以字符而不是元素排序。空字符串被认为比不匹配要长。例如:bb*匹配abbbc的三个中间字符; (week|wee)(night|knights)匹配weeknights的所有十个字符;当(.*).*abc匹配时,带括号的子表达式会匹配所有三个字符;当(a*)*bc匹配时,整个 RE 和带括号的子表达式都匹配一个空字符串。

如果指定了不区分大小写的匹配,则效果就好像所有区分大小写都从字母表中消失了一样。当在多种情况下存在的字母显示为括号表达式之外的普通字符时,它会有效地转换为包含两种情况的括号表达式,例如x变为[xX]。当它出现在方括号表达式中时,所有与之对应的大小写都添加到方括号表达式中,例如[x]变为[xX],而[^x]变为[^xX]

如果指定了对换行敏感的匹配,则使用_的.和方括号表达式将永远不会与换行符匹配(因此,除非 RE 明确将其匹配,否则匹配将不会越过换行符),并且^$将分别匹配换行符之后和之前的空字符串。 ,以及分别在字符串的开头和结尾匹配。但是 ARE 转义符\A\Zcontinue 匹配字符串* only *的开头或结尾。

如果指定了部分对换行符敏感的匹配,则与对换行符敏感的匹配一样,这会影响.和方括号表达式,但不会影响^$

如果指定了反向部分对换行符敏感的匹配,则对^$的影响与对换行敏感的匹配一样,但对.和方括号表达式没有影响。这不是很有用,但是是为了对称而提供的。

9 .7.3.6. 限制和兼容性

在此实现中,对 RE 的长度没有特别的限制。但是,旨在具有高度可移植性的程序不应使用超过 256 字节的 RE,因为 POSIX 兼容的实现可以拒绝接受此类 RE。

实际上与 POSIX ERE 不兼容的 ARE 的唯一功能是\不会在方括号表达式内失去其特殊的意义。所有其他 ARE 功能均使用非法语法,或在 POSIX ERE 中具有未定义或未指定作用的语法;对于 BRE 和 ERE,director 的***语法同样在 POSIX 语法之外。

许多 ARE 扩展都是从 Perl 借来的,但是有些已被更改以清理它们,并且不存在一些 Perl 扩展。注意的不兼容性包括\b\B,对尾随的换行符没有特殊处理,对受换行符敏感的匹配影响的事物添加了补充的括号表达式,对括号的限制以及在前向/后向约束中的后向引用的限制,以及最长的/ shortest-match(而不是 first-match)匹配语义。

PostgreSQL 7.4 之前的版本认识到 ARE 与 ERE 语法之间存在两个重大不兼容性:

  • 在 ARE 中,\后跟字母数字字符是转义字符或错误,而在以前的版本中,这只是写字母数字的另一种方式。这应该没什么大问题,因为没有理由在早期版本中编写这样的序列。

  • 在 ARE 中,\仍是[]内的特殊字符,因此必须将方括号表达式中的 Literals\写为\\

9 .7.3.7. 基本正则表达式

BRE 在几个方面与 ERE 不同。在 BRE 中,|+?是普通字符,没有等效的功能。边界的定界符是\{\},而{}本身就是普通字符。嵌套子表达式的括号是\(\),而()本身就是普通字符。 ^是除 RE 开头或带括号的子表达式的开头之外的普通字符,$是除 RE 末尾或带括号的子表达式的结尾之外的普通字符,并且*如果出现在 RE 的末尾,则是普通字符。 RE 的开头或带括号的子表达式的开头(在可能的前导^之后)。最后,可以使用个位数的反向引用,并且\<\>分别是[[:<:]][[:>:]]的同义词; BRE 中没有其他可用的转义符。