↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1
历史版本。 PostgreSQL 7.1 已结束支持。 请参阅 当前版本手册.

4.5. 模式匹配 #

Postgres 提供了两种独立的模式匹配方法:SQL 的 LIKE 操作符和 POSIX 风格的正则表达式。

提示

如果你的模式匹配需求超出了这些,或者想进行由模式驱动的替换或翻译,可以考虑用 Perl 或 Tcl 编写用户定义的函数。

4.5.1. 使用 LIKE 进行模式匹配 #

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

每个 pattern(模式)都定义了一个字符串集合。如果 string(字符串)包含在 pattern 所表示的字符串集合中,LIKE 表达式就返回真。(与预期的一样,如果 LIKE 返回真,NOT LIKE 表达式就返回假,反之亦然。等价的表达式是 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子句选择其他转义字符。要匹配转义字符本身,请写两个转义字符。

注意,反斜线在字符串常量中本来就有特殊含义,因此要写一个包含反斜线的模式常量,必须在查询中写两个反斜线。

可以使用关键字 ILIKE 代替 LIKE,按照当前的区域设置使匹配不区分大小写。这不是 SQL 标准的内容,而是 Postgres 的扩展。

操作符~~等效于 LIKE,而~~*对应 ILIKE。还有 !~~ 和 !~~* 操作符分别代表 NOT LIKE 和 NOT ILIKE。所有这些操作符都是 Postgres 特有的。

4.5.2. POSIX正则表达式 #

表 4.8. 正则表达式匹配操作符

操作符描述示例
~ 匹配正则表达式,区分大小写'thomas' ~ '.*thomas.*'
~* 匹配正则表达式,不区分大小写'thomas' ~* '.*Thomas.*'
!~ 不匹配正则表达式,区分大小写'thomas' !~ '.*Thomas.*'
!~* 不匹配正则表达式,不区分大小写'thomas' !~* '.*vadim.*'

POSIX 正则表达式提供了比 LIKE 函数更强大的模式匹配手段。许多 Unix 工具(如 egrep、sed 或 awk)使用的模式匹配语言与此处描述的类似。

正则表达式是一个字符序列,它是一个字符串集合(正则集)的缩写定义。如果一个字符串是正则表达式所描述的正则集中的成员,就说该字符串匹配这个正则表达式。与 LIKE 一样,模式字符与字符串字符精确匹配,除非它们是正则表达式语言中的特殊字符—— 但正则表达式使用的特殊字符与 LIKE 不同。与 LIKE 模式不同的是,除非正则表达式被显式地锚定到字符串的开头或结尾,否则正则表达式可以匹配字符串中任意位置的内容。

正则表达式(RE)按 POSIX 1003.2 的定义有两种形式:现代 RE(大致相当于 egrep 的那些;1003.2 称之为“扩展” RE)和过时的 RE(大致相当于 ed 的那些;1003.2 的“基本” RE)。Postgres 实现的是现代形式。

一个(现代)RE 是一个或多个非空分支,由 | 分隔。它能匹配其中任何一个分支所能匹配的内容。

一个分支是一个或多个片段的串接。它匹配第一个片段的一个匹配后跟第二个片段的一个匹配,依此类推。

一个片段是一个原子,后面可能跟着一个 *、+、? 或界限。原子后跟 * 匹配该原子的 0 个或多个匹配组成的序列。原子后跟 + 匹配该原子的 1 个或多个匹配组成的序列。原子后跟 ? 匹配该原子的 0 个或 1 个匹配组成的序列。

一个界限是 { 后跟一个无符号十进制整数,后面可能跟 ,,再后面可能跟另一个无符号十进制整数,最后总是跟 }。这些整数必须在 0 到 RE_DUP_MAX(255)之间(含),如果有两个整数,第一个不能超过第二个。原子后跟含一个整数 i 而没有逗号的界限匹配恰好 i 个该原子的匹配组成的序列。原子后跟含一个整数 i 和一个逗号的界限匹配 i 个或更多个该原子的匹配组成的序列。原子后跟含两个整数 i 和 j 的界限匹配 i 到 j(含)个该原子的匹配组成的序列。

注意

重复操作符(?、*、+ 或界限)不能跟在另一个重复操作符后面。重复操作符不能作为表达式或子表达式的开头,也不能跟在 ^ 或 | 后面。

一个原子是一个由 () 括起来的正则表达式(匹配该正则表达式的一个匹配)、一个空的 ()(匹配空串)、一个方括号表达式(见下文)、.(匹配任意单个字符)、^(匹配输入字符串开头的空串)、$(匹配输入字符串结尾的空串)、一个 \ 后跟 ^.[$()|*+?{\ 中的一个字符(匹配作为普通字符的该字符)、一个 \ 后跟其他任何字符(匹配作为普通字符的该字符,如同 \ 不存在一样),或者一个没有其他含义的单个字符(匹配该字符)。一个 { 后跟非数字字符时是普通字符,不是界限的开始。以 \ 结束一个 RE 是非法的。

注意,反斜线(\)在字符串常量中本来就有特殊含义,因此要写一个包含反斜线的模式常量,必须在查询中写两个反斜线。

方括号表达式是一个由 [] 括起来的字符列表。它通常匹配列表中的任意单个字符(但见下文)。如果列表以 ^ 开头,则匹配任意一个不在列表其余部分中的单个字符。如果列表中的两个字符由 - 分隔,这是按整理序列位于这两个字符之间(含)的完整字符范围的简写形式,例如在 ASCII 中 [0-9] 匹配任意十进制数字。两个范围共享一个端点是非法的,例如 a-c-e。范围非常依赖于整理序列,因此可移植的程序应当避免依赖它们。

要在列表中包含字面字符 ],可以让它作为第一个字符(跟在可能的 ^ 之后)。要包含字面字符 -,可以让它作为第一个或最后一个字符,或者一个范围的第二个端点。要把字面 - 用作范围的第一个端点,可以把它放在 [. 和 .] 中使它成为一个排序元素(见下文)。除了这些和某些使用 [ 的组合(见下一段)之外,所有其他特殊字符,包括 \,在方括号表达式内都失去它们的特殊含义。

在方括号表达式中,排序元素(一个字符、一个排序时如同单个字符的多字符序列或者一个排序序列名)放在 [. 和 .] 中,表示该排序元素的一个实例。序列 [.characters.] 在当前区域设置下作为一个字符排序。

在方括号表达式里,包围在[=和=]里的排序元素是一个等价类,代表等效于那一个的所有排序元素的字符序列,包括它本身(如果没有其它等效排序元素,那么就好像封装定界符是[.和 .])。例如,如果o和^是一个等价类的成员,那么[[=o=]]、[[=^=]]和[o^]都是同义的。一个等价类不能是一个范围的端点。

在方括号表达式中,用 [: 和 :] 括起的字符类名表示属于该类的所有字符的列表。标准字符类名包括:alnum、alpha、blank、cntrl、digit、graph、lower、print、punct、space、upper、xdigit。它们表示 ctype 中定义的字符类。区域设置可以提供其他字符类。字符类不能用作范围的端点。

方括号表达式有两个特例:方括号表达式 [[:<:]] 和 [[:>:]] 分别匹配一个单词开头和结尾的空串。单词定义为前后都没有单词字符的单词字符序列。单词字符是 alnum 字符(由 ctype 定义)或下划线。这是一个与 POSIX 1003.2 兼容但未由其规定的扩展,在打算移植到其他系统的软件中应谨慎使用。

在一个 RE 可以匹配给定字符串的多个子串的情况下,RE 匹配在字符串中最先开始的那个。如果 RE 可以匹配从该点开始的多个子串,它匹配最长的那个。在整个匹配尽可能长的约束之下,子表达式也匹配最长的可能子串,在 RE 中靠前的子表达式比靠后的优先。注意,高层子表达式因而比其低层的组成子表达式优先。

匹配长度是以字符衡量的,而不是以排序元素。空串被认为比完全不匹配长。例如,bb* 匹配 abbbc 的中间三个字符,(wee|week)(knights|nights) 匹配 weeknights 的全部十个字符,当 (.*).* 与 abc 匹配时,带圆括号的子表达式匹配全部三个字符,而当 (a*)* 与 bc 匹配时,整个 RE 和带圆括号的子表达式都匹配空串。

如果指定不区分大小写的匹配,其效果非常类似于字母表中的所有大小写差别都消失了。当存在多种大小写形式的字母作为普通字符出现在方括号表达式之外时,它实际上被转换为包含两种大小写形式的方括号表达式,例如 x 变成 [xX]。当它出现在方括号表达式内部时,它的所有大小写对应字符都被加入该方括号表达式,因此(例如)[x] 变成 [xX],[^x] 变成 [^xX]。

RE 的长度没有特定的限制,除了内存有限之外。内存使用量与 RE 大小大致成线性关系,并且很大程度上对 RE 的复杂度不敏感,有界重复除外。有界重复通过宏展开实现,如果计数很大或有界重复嵌套,它在时间和空间上的代价都很高。像 ((((a{1,100}){1,100}){1,100}){1,100}){1,100} 这样的 RE 会(最终)耗尽几乎任何现有机器的交换空间。 [2]



[2] 注意这是 1994 年写的。数字可能已经变了,但问题依然存在。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.