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 正则表达式借用的模式匹配元字符:
-
|
表示选择(两个候选之一)
-
*
表示重复前面的项零次或更多次
-
+
表示重复前面的项一次或更多次
-
?
表示重复前面的项零次或一次
-
{
m
}
表示重复前面的项正好
m
次
-
{
m
,}
表示重复前面的项
m
或更多次
-
{
m
,
n
}
表示重复前面的项至少
m
次,最多不超过
n
次
-
Parentheses
()
把项组合成一个逻辑项
-
[...]
声明一个字符类,只在POSIX正则表达式中
请注意点(
.
)对于
SIMILAR TO
来说不是元字符。
和
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
表 9-12
列出了所有用于 POSIX 正则表达式的操作符。
表 9-12. 正则表达式匹配操作符
操作符
|
描述
|
例子
|
~
|
匹配正则表达式,大小写相关
|
'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
POSIX
模式语言将在下面详细描述。
带两个参数的
substring(
string
from
pattern
)
函数提供了从字符串中抽取一个匹配 POSIX 正则表达式模式的子字符串的方法。
如果没有匹配它返回 NULL ,否则就是文本中匹配模式的那部分。
但是如果该模式包含任何圆括弧,那么将返回匹配第一对子表达式(对应第一个左圆括弧的)的文本。
如果你想在表达式里使用圆括弧而又不想导致这个例外,
那么你可以在整个表达式外边放上一对圆括弧。如果你需要在想抽取的子表达式前有圆括弧,
参阅描述的非捕获性圆括弧。
一些例子:
substring('foobar' from 'o.b') oob
substring('foobar' from 'o(.)b') o
regexp_replace
(
source
,
pattern
,
replacement
[
,
flags
])函数提供了将匹配 POSIX
正则表达式模式的子字符串替换为新文本的功能。如果没有匹配 pattern 的子字符串,
那么返回不加修改的
source
字符串。如果有匹配,
则返回的
source
字符串里面的对应子字符串将被
replacement
字符串替换掉。
replacement
字符串可以包含
\
n
,
这里的
n
是 1 到 9 ,表明源字符串中匹配第
n
个圆括弧子表达式的部分将插入在该位置,并且它可以包含
\&
表示应该插入匹配整个模式的字符串。如果你需要放一个文本反斜杠在替换文本里,
那么写
\\
。可选的
flags
参数包含零个或多个改变函数行为的单字母标记。
i
表示进行大小写无关的匹配,
g
表示替换每一个匹配的子字符串而不仅仅是第一个。支持的标记(不是
g
)在
表 9-20
中描述。
一些例子:
regexp_replace('foobarbaz', 'b..', 'X')
fooXbaz
regexp_replace('foobarbaz', 'b..', 'X', 'g')
fooXX
regexp_replace('foobarbaz', 'b(..)', E'X\\1Y', 'g')
fooXarYXazY
regexp_matches
(
string
,
pattern
[
,
flags
])函数返回一个从匹配POSIX正则表达式模式中获取的所有子串结果的text数组。
这个函数可以返回零行,一行,或者多行(参阅下面的
g
标记)。如果
pattern
没有匹配,则函数返回零行。如果模式包含没有括号的子表达式,则每行返回的是单元素的文本数组,
其中包含的子串相匹配整个模式。如果模式包含有括号的子表达式,函数返回一个文本数组,它的第
n
个元素是子串匹配模式括号子表达式内的第
n
个元素。
(不计
"非捕获"
的括号;详细信息参阅下面)。参数
flags
是一个可选的text字符串,
含有0或者更多单字母标记来改变函数行为。标记
g
导致查找字符串中的每个匹配,而不仅是第一个,
每个匹配返回一行,支持的标记(不是
g
)在
表 9-20
里描述。
一些例子:
SELECT regexp_matches('foobarbequebaz', '(bar)(beque)');
regexp_matches
----------------
{bar,beque}
(1 row)
SELECT regexp_matches('foobarbequebazilbarfbonk', '(b[^b]+)(b[^b]+)', 'g');
regexp_matches
----------------
{bar,beque}
{bazil,barf}
(2 rows)
SELECT regexp_matches('foobarbequebaz', 'barbeque');
regexp_matches
----------------
{barbeque}
(1 row)
使用select子句,可能强制
regexp_matches()
总是返回一行;
当你想要返回
SELECT
目标列表中的所有行,甚至没有匹配的情况下,是有特别有用的。
SELECT col1, (SELECT regexp_matches(col2, '(bar)(beque)')) FROM tab;
regexp_split_to_table
(
string
,
pattern
[
,
flags
])函数使用POSIX正则表达式模式作为分隔符,分隔字符串。
如果没有匹配
pattern
,函数将返回
string
。如果有至少一个匹配,
每个匹配返回从最后一个匹配结束(或者字符串的开头)到匹配开始的文本。当没有更多的匹配,
返回最后一个匹配的结束到字符串的结束的文本。
flags
参数是一个可选text字符串,
含有0或者更多单字母标记来改变函数行为。
regexp_split_to_table
支持的标记在
表 9-20
里描述。
除了
regexp_split_to_array
返回结果为text数组,
regexp_split_to_array
函数行为与
regexp_split_to_table
相同,使用语法
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', E'\\s+') AS foo;
-------
quick
brown
jumps
(9 rows)
SELECT regexp_split_to_array('the quick brown fox jumps over the lazy dog', E'\\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', E'\\s*') AS foo;
-----
(16 rows)
作为最后一个例子表明,发生在字符串的开始或结束或紧接前一个的匹配,regexp分隔函数忽略零长度匹配,
这样实现
regexp_matches
严格上来说是违背了的正则表达式匹配的定义,但在实际使用中,
通常是最便利的的行为。如Perl等软件系统,使用了类似的定义。
PostgreSQL
的正则表达式使用 Henry Spencer 写的一个包来实现。
下面的大部分描述都是从他的手册页里逐字拷贝过来的。
正则表达式(
RE
s),在
POSIX
1003.2中定义,
它有两种形式:
扩展
RE
或
ERE
(基本上就是在
egrep
里的那些),
基本
RE
或
BRE
(基本上就是在
ed
里的那些)。
PostgreSQL
两种形式都实现了,并且还做了一些 POSIX 里面没有的,
但是因为在类似 Perl 或者 Tcl 这样的语言中得到广泛应用的一些扩展。
使用了那些非 POSIX 扩展的正则表达式叫
高级
RE
或
ARE
。ARE 几乎完全是 ERE 的超集,但是 BRE 有几个符号上的不兼容(以及更多的限制)。
我们首先描述 ARE 和 ERE 形式,描述那些只适用于 ARE 的特性,然后描述与 BRE 的区别是什么。
注意:
PostgreSQL
总是初始化一个遵循ARE规则的正则表达式。然而,
更多限制的ERE或BRE规则可以通过在RE模式前放置一个
embedded option
来选择,
描述在
第 9.7.3.4 节
。这对于期望完全兼容
POSIX
1003.2规则的应用程序是有用的。
一个正则表达式定义为一个或多个
分支
,
由
|
分隔。它匹配其中任何一个分支的东西。
一个分支是零个或多个
有修饰的原子
或
约束
连接而成。
一个原子匹配第一个,后面的原子匹配第二个,以此类推;一个空分支匹配空字符串。
一个有修饰的原子是一个
原子
,后面可能跟着一个
量词
。
没有量词的时候,它匹配一个原子,有量词的时候,它可以匹配若干个原子。
原子
可以是在
表 9-13
里面显示的任何可能。
可能的量词和他们的含义在
表 9-14
里显示。
一个
约束
匹配一个空字符串,但只是在满足特定条件下才匹配。
约束可以在能够使用原子的地方使用,只是它不能跟着量词。
最简单的原子在
表 9-15
里显示;更多的约束稍后描述。
表 9-13. 正则表达式原子
原子
|
描述
|
(
re
)
|
(
re
是任意正则表达式)匹配一个对
re
的匹配,有可报告的匹配信息。
|
(?:
re
)
|
同上,但是匹配不会被报告(一个
"非捕获"
圆括弧),只在 ARE 中有。
|
.
|
匹配任意单个字符
|
[
chars
]
|
一个
方括弧表达式
,匹配任意的
字符
(参阅
第 9.7.3.2 节
获取更多细节)
|
\
k
|
(
k
是非字母数字字符)匹配一个当作普通字符看待的特定字符,
比如
\\
匹配一个反斜杠。
|
\
c
|
c
是一个字母数字(可能跟着其它字符),它是一个
转义
,
参阅
第 9.7.3.3 节
。仅存在于 ARE 中;在 ERE 和 BRE 中,
它匹配
c
。
|
{
|
如果后面跟着一个非数字字符,那么就匹配左花括弧
{
;
如果跟着一个数字,那么它是
范围
的开始(见下面)
|
x
|
这里的
x
是一个没有其它特征的单个字符,则匹配该字符
|
RE不能以(
\
)结尾。
表 9-14. 正则表达式量词
量词
|
匹配
|
*
|
一个匹配 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 中可用)匹配对应的正常(
贪婪
)模式,
区别是它寻找最少的匹配,而不是最多的匹配。参阅
第 9.7.3.5 节
获取细节。
注意:
一个量词不能紧跟在另外一个量词后面,例如,
**
是非法的。
量词不能是表达式或者子表达式的开头,也不能跟在
^
或
|
后面。
表 9-15. 正则表达式约束
约束
|
描述
|
^
|
匹配字符串的开头
|
$
|
匹配字符串的结尾
|
(?=
re
)
|
正前瞻
匹配任何匹配
re
的子字符串起始点(只在 ARE 中有)
|
(?!
re
)
|
负前瞻
匹配任何不匹配
re
的子字符串起始点(只在 ARE 中有)
|
前瞻约束不能包含
后引用
(参阅
第 9.7.3.3 节
),
并且在其中的所有圆括弧都被认为是不捕获的。
方括弧表达式
是一个包围在
[]
里的字符列表。
它通常匹配任意单个列表中的字符(又见下文)。如果列表以
^
开头,
它匹配任意单个(又见下文)
不在
该列表中的字符。如果该列表中两个字符用
-
隔开,那它就是那两个字符(包括在内)之间的所有字符范围的缩写,
比如,在
ASCII
里
[0-9]
包含任何十进制数字。
两个范围共享一个终点是非法的,比如
a-c-e
。这个范围与字符集关系密切,
可移植的程序不应该依靠它们。
想在列表中包含文本
]
,可以让它做列表的首字符(如果用到了,
跟在
^
后面)。想在列表中包含文本
-
,
可以让它做列表的首字符或者末字符,或者一个范围的第二个终点。
想在列表中把文本
-
当做范围的起点,把它用
[.
和
.]
包围起来,这样它就成为一个集合元素(见下文)。
除了这些字符本身,和一些用
[
的组合(见下段),
以及转义(只在 ARE 中有效)以外,所有其它特殊字符在方括弧表达式里都失去它们的特殊含义。
特别是,在 ERE 和 BRE 规则下
\
不是特殊的,但在 ARE 里,
它是特殊的(还是引入一个转义)。
在一个方括弧表达式里,一个集合元素(一个字符、一个当做一个字符的多字符序列、
或者一个表示上面两种情况的集合序列)包含在
[.
和
.]
里面的时候表示该集合元素的字符序列。该序列是该方括弧列表的一个元素。
这允许一个包含多字符集合元素的方括弧表达式就可以匹配多于一个字符,比如,
如果集合序列包含一个
ch
集合元素,那么
[[.ch.]]*c
匹配
chchcc
的头五个字符。译注:其实把 [. 和 .] 括起来的整体当一个字符看就行了。
注意:
PostgreSQL
目前不支持多字符集合元素。这些信息描述了将来可能有的行为。
在方括弧表达式里,在
[=
和
=]
里包围的集合元素是一个
等效表
,代表等于这里所有集合元素的字符序列,
包括它本身(如果没有其它等效集合元素,那么就好像封装元素是
[.
和
.]
)。比如,如果
o
和
^
是一个等效表的成员,那么
[[=o=]]
,
[[=^=]]
,
[o^]
都是同义的。一个等效表不能是一个范围的端点。
在方括弧表达式里,在
[:
和
:]
里面封装的字符表名字代表属于该表的所有字符的列表。标准的字符表名字是:
alnum
,
alpha
,
blank
,
cntrl
,
digit
,
graph
,
lower
,
print
,
punct
,
space
,
upper
,
xdigit
。
它们代表在
ctype
里定义的字符表。本地化设置可能会提供其它的表。字符表不能用做一个范围的端点。
在方括弧表达式里有两个特例:方括弧表达式
[[:<:]]
和
[[:>:]]
是约束,分别匹配一个单词开头和结束的空串。
单词定义为一个单词字符序列,前面和后面都没有其它单词字符。
单词字符是一个
alnum
字符(和
ctype
里定义的一样)或者一个下划线。这是一个扩展,兼容
POSIX
1003.2 ,
但那里面并没有说明,而且在准备移植到其它系统里去的软件里一定要小心使用。
通常下面描述的约束转义更好些;他们并非更标准,但是更容易输入。
在正则表达式可以匹配给出的字符串中多于一个子字符串的情况下,
正则表达式匹配字符串中最靠前的那个子字符串。
如果正则表达式可以匹配在那个位置开始的多个子字符串,要么是取最长的子字符串,
要么是最短的,具体哪种,取决于正则表达式是
贪婪
的还是
非贪婪
的。
一个正则表达式是否贪婪取决于下面规则:
-
大多数原子,以及所有约束,都没有贪婪属性(因为它们毕竟无法匹配个数变化的文本)。
-
在一个正则表达式周围加上圆括弧并不会改变其贪婪性。
-
一个带一个固定重复次数的量词(
{
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
,
对结尾的新行缺乏特别的处理,对那些新行敏感匹配的附加的补齐方括弧表达式,
在前瞻约束里对圆括弧和方括弧引用的限制,以及最长/最短匹配(而不是第一匹配)语义。
PostgreSQL
7.4 之前的版本里的 ARE 和 ERE 存在两个非常显著的不兼容:
BRE 在几个方面和 ERE 不太一样。在BRE里,
|
,
+
,
?
都是普通字符,它们没有等效的功能替换。范围的分隔符是
\{
和
\}
,
因为
{
和
}
本身是普通字符。嵌套的子表达式的圆括弧是
\(
和
\)
,因为
(
和
)
自身是普通字符。
除非在正则表达式开头或者是圆括弧封装的子表达式开头,
^
都是普通字符,
除非在正则表达式结尾或者是圆括弧封装的子表达式的结尾,
$
是一个普通字符,
而如果
*
出现在正则表达式开头或者是圆括弧封装的子表达式开头
(前面可能有
^
),那么它是个普通字符。最后,可以用单数字的后引用,
以及
\<
和
\>
分别是
[[:<:]]
和
[[:>:]]