↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 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 已于 2006 年 4 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

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 年写的。数字 可能已经变了,但问题 依然存在。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。