?
Ce document utilise Manuel du site Web PHP chinois Libérer
PostgreSQL提供了三種實(shí)現(xiàn)模式匹配的方法:傳統(tǒng)SQL的LIKE
操作符、SQL99
新增的SIMILAR TO
操作符、POSIX風(fēng)格的正則表達(dá)式。另外還有一個(gè)模式匹配函數(shù)substring可用,
它可以使用SIMILAR TO
風(fēng)格或者POSIX風(fēng)格的正則表達(dá)式。
除了基本" ?"操作符,函數(shù)可用于提取或替換匹配的子串和分隔匹配位置的字符串。
Tip: 如果你的模式匹配要求比這些還多,或者想寫一些模式驅(qū)動(dòng)的替換和轉(zhuǎn)換,請(qǐng)考慮用Perl或Tcl寫一個(gè)用戶定義函數(shù)。
LIKE
stringLIKEpattern[ESCAPEescape-character] stringNOT LIKEpattern[ESCAPEescape-character]
如果該string與所提供的pattern模式匹配,
那么LIKE
表達(dá)式返回真。和我們想像的一樣,如果LIKE
返回真,
那么NOT LIKE
表達(dá)式將返回假,反之亦然。一個(gè)等效的表達(dá)式
是NOT(stringLIKEpattern)。
如果pattern不包含百分號(hào)或者下劃線,那么該模式只代表它本身;這時(shí)候LIKE
的行為就像等號(hào)操作符。
在pattern里的下劃線(_)匹配任何單個(gè)字符;而一個(gè)百分號(hào)(%)匹配零或多個(gè)任何字符。
一些例子:
'abc' LIKE 'abc' true 'abc' LIKE 'a%'true 'abc' LIKE '_b_' true 'abc' LIKE 'c' false
LIKE
模式匹配總是覆蓋整個(gè)字符串。要匹配在字符串內(nèi)部任何位置的序列,該模式必須以百分號(hào)開頭和結(jié)尾。
要匹配下劃線或者百分號(hào)本身,在pattern里相應(yīng)的字符必須前導(dǎo)逃逸字符。 缺省的逃逸字符是反斜杠,但是你可以用ESCAPE子句指定一個(gè)。要匹配逃逸字符本身,寫兩個(gè)逃逸字符。
請(qǐng)注意反斜杠在字符串文本里已經(jīng)有特殊含義了,所以如果你寫一個(gè)包含反斜杠的模式常量,
那你就要在 SQL 語句里寫兩個(gè)反斜杠。因此,寫一個(gè)匹配單個(gè)反斜杠的模式實(shí)際上要在語句里
寫四個(gè)反斜杠。你可以通過用ESCAPE選擇一個(gè)不同的逃逸字符來避免這樣;這樣反斜杠就
不再是LIKE
的特殊字符了。(但仍然是字符文本分析器的特殊字符,所以你還是需要兩個(gè)反斜杠。)
我們也可以通過寫成ESCAPE ''的方式關(guān)閉逃逸機(jī)制,這時(shí),我們就不能關(guān)閉下劃線和百分號(hào)的特殊含義
關(guān)鍵字ILIKE可以用于替換LIKE, 令該匹配就當(dāng)前的區(qū)域設(shè)置是大小寫無關(guān)的。這個(gè)特性不是SQL標(biāo)準(zhǔn), 是PostgreSQL擴(kuò)展。
操作符~~等效于LIKE
,而~~*等效于ILIKE
。
還有!~~和!~~*操作符分別
代表NOT LIKE
和NOT ILIKE
。所有這些操作符都是PostgreSQL特有的。
SIMILAR TO
正則表達(dá)式stringSIMILAR TOpattern[ESCAPEescape-character] stringNOT SIMILAR TOpattern[ESCAPEescape-character]
SIMILAR TO
根據(jù)自己的模式是否匹配給定字符串而返回真或假。
它和LIKE
非常類似,只不過它使用 SQL 標(biāo)準(zhǔn)定義的正則表達(dá)式理解模式。
SQL 標(biāo)準(zhǔn)的正則表達(dá)式是在LIKE
表示法和普通的正則表達(dá)式表示法之間古怪的交叉。
類似LIKE
, theSIMILAR TO
操作符只有在它的模式匹配整個(gè)字符串的時(shí)候才能成功;
這一點(diǎn)和普通的正則表達(dá)式的習(xí)慣不同,在普通的正則表達(dá)式里,模式匹配字符串的任意部分。
和LIKE
類似的地方還有SIMILAR TO
使用
_ 和 % 分別匹配單個(gè)字符和任意字符串(這些和 POSIX 正則表達(dá)式里的_和%兼容)。
除了這些從 LIKE 借用的功能之外,SIMILAR TO
支持下面這些從 POSIX 正則表達(dá)式借用的模式匹配元字符:
|表示選擇(兩個(gè)候選之一).
*表示重復(fù)前面的項(xiàng)零次或更多次
+表示重復(fù)前面的項(xiàng)一次或更多次
? 表示重復(fù)前面的項(xiàng)零或一次。
{m} 表示重復(fù)前面的項(xiàng),完全相同m次。
{m,} 表示重復(fù)前面的項(xiàng)m或更多次。
{m,n} 表示重復(fù)前面的項(xiàng)至少m次,不超過n次。
括號(hào)()可以作為項(xiàng)目分組到一個(gè)獨(dú)立的邏輯項(xiàng)。
[...]聲明一個(gè)字符類,就像POSIX正則表達(dá)式。
請(qǐng)注意之間的 (.)不是一個(gè)元字符而是SIMILAR TO
。
和LIKE
一樣,反斜杠關(guān)閉所有這些元字符的特殊含義;
當(dāng)然我們也可以用ESCAPE聲明另外一個(gè)逃逸字符。
一些例子:
'abc' SIMILAR TO 'abc' true 'abc' SIMILAR TO 'a' false 'abc' SIMILAR TO '%(b|d)%'true 'abc' SIMILAR TO '(b|c)%'false
三個(gè)參數(shù)的substring(string from pattern for escape-character)
函數(shù)提供了
一個(gè)從字符串中抽取一個(gè)匹配 SQL 正則表達(dá)式模式的子字符串功能。和SIMILAR TO一樣,
聲明的模式必須匹配整個(gè)字符串,否則函數(shù)失效并返回 NULL 。為了標(biāo)識(shí)在成功的時(shí)候應(yīng)該返回的模式部分,
模式必須出現(xiàn)后跟雙引號(hào)(")的兩個(gè)逃逸字符。匹配這兩個(gè)標(biāo)記之間的模式的字符串將被返回。
一些例子,用#"分隔返回字符串:
substring('foobar' from '%#"o_b#"%' for '#')oob substring('foobar' from '#"o_b#"%' for '#') NULL
Table 9-11列出了所可用的POSIX 正則表達(dá)式的模式匹配操作符
Table 9-11. 正則表達(dá)式匹配操作符
操作符 | 描述 | 示例 |
---|---|---|
~ | 匹配正則表達(dá)式,區(qū)分大小寫 | 'thomas' ~ '.*thomas.*' |
~* | 匹配正則表達(dá)式,不分大小寫 | 'thomas' ~* '.*Thomas.*' |
!~ | 不匹配正則表達(dá)式,區(qū)分大小寫 | 'thomas' !~ '.*Thomas.*' |
!~* | 不匹配正則表達(dá)式,不分大小寫 | 'thomas' !~* '.*vadim.*' |
POSIX正則表達(dá)式提供了比LIKE
和SIMILAR TO
操作符更強(qiáng)大的模式匹配的方法。許多 Unix 工具,比如egrep,
sed,awk使用類似的模式匹配語言。
正則表達(dá)式是一個(gè)字符序列,它是定義一個(gè)字符串集合(一個(gè)正則集合)的縮寫。
如果一個(gè)字符串是正則表達(dá)式描述的正則集合中的一員時(shí),我們就說這個(gè)字符串匹配該正則表達(dá)式。
和LIKE
一樣,模式字符準(zhǔn)確地匹配字符串字符,除非在正則表達(dá)式語言里有特殊
字符(不過正則表達(dá)式用的特殊字符和LIKE
用的不同)。和LIKE
不一樣的是,
正則表達(dá)式可以匹配字符串里的任何位置,除非該正則表達(dá)式明確地錨定在字符串的開頭或者結(jié)尾。
一些例子:
'abc' ~ 'abc' true 'abc' ~ '^a'true 'abc' ~ '(b|d)'true 'abc' ~ '^(b|c)'false
下面更詳細(xì)描述POSIX模式匹配語言。
兩個(gè)參數(shù)的substring(stringfrom
pattern)
函數(shù)提供了從字符串中抽取一個(gè)
匹配 POSIX 正則表達(dá)式模式的子字符串的方法。如果沒有匹配它返回 NULL ,
否則就是文本中匹配模式的那部分。但是如果該模式包含任何圓括弧,那么將返回匹配
第一對(duì)子表達(dá)式(對(duì)應(yīng)第一個(gè)左圓括弧的)的文本。如果你想在表達(dá)式里使用圓括弧而又不想
導(dǎo)致這個(gè)例外,那么你可以在整個(gè)表達(dá)式外邊放上一對(duì)圓括弧。
如果你需要在想抽取的子表達(dá)式前有圓括弧,參閱描述的非捕獲性圓括弧。
一些例子:
substring('foobar' from 'o.b')oob substring('foobar' from 'o(.)b')o
regexp_replace
(source,
pattern,replacement
[,flags]) 函數(shù)提供了將匹配
POSIX 正則表達(dá)式模式的子字符串替換為新文本的功能。如果沒有匹配pattern的子字符串,
那么返回不加修改的source字符串。如果有匹配,則返回的source字符串里面的對(duì)應(yīng)子字符串
將被 replacement 字符串替換掉。replacement字符串可以包含\n,
這里的n是1到9,
表明源字符串中匹配第n個(gè)圓括弧子表達(dá)式的部分將插入在該位置,并且它可以包含\&表示
應(yīng)該插入匹配整個(gè)模式的字符串。如果你需要放一個(gè)文本反斜杠在替換文本里,那么寫\\(和
通常一樣,記得在文本常量字符串里寫雙反斜杠)。可選的flags參數(shù)包含零個(gè)或多個(gè)改變函數(shù)行為的單字母標(biāo)記。
i表示進(jìn)行大小寫無關(guān)的匹配,g表示替換每一個(gè)匹配的子字符串而不僅僅是第一個(gè)。
其它支持的標(biāo)記描述在Table 9-19。
一些例子:
regexp_replace('foobarbaz', 'b..', 'X') fooXbaz regexp_replace('foobarbaz', 'b..', 'X', 'g') fooXX regexp_replace('foobarbaz', 'b(..)', E'X\\1Y', 'g') fooXarYXazY
regexp_matches
函數(shù)返回一個(gè)所有匹配POSIX正則表達(dá)式的獲取子串結(jié)果的text數(shù)組。使用語法
regexp_matches
(string,pattern
[,flags])。這個(gè)函數(shù)可以返回沒有行,一行,或者多行
(參閱下面的g標(biāo)記)。如果pattern沒有匹配,則函數(shù)返回沒有行。
如果模式包含沒有括號(hào)的子表達(dá)式,則每行返回的是單元素的文本數(shù)組,其中包含的子串相匹配整個(gè)模式。
如果模式包含括號(hào)的子表達(dá)式,函數(shù)返回一個(gè)文本數(shù)組,n的元素是子串匹配n括號(hào)子表達(dá)式內(nèi)的模式。
(不計(jì)"非捕獲"的括號(hào));詳細(xì)信息參閱下面的。
參數(shù)flags是一個(gè)選項(xiàng)text字符串,含有0或者更多單字母標(biāo)記來改變函數(shù)行為。標(biāo)記g導(dǎo)致查找字符串中的每個(gè)匹配,
而不僅是第一個(gè),每個(gè)匹配返回一行,其它的標(biāo)記支持描述在Table 9-19。
一些例子:
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子句,可能強(qiáng)制regexp_matches()
總是返回一行;
在SELECT當(dāng)你想要的所有行的目標(biāo)列表返回,甚至不匹配的情況下,是有特別有用的。
SELECT col1, (SELECT regexp_matches(col2, '(bar)(beque)')) FROM tab;
regexp_split_to_table
函數(shù)使用POSIX正則表達(dá)式作為分隔符,分隔字符串。
語法regexp_split_to_table
(string,pattern
[,flags])。如果沒有匹配pattern,函數(shù)將返回string。
如果有至少一個(gè)匹配,每個(gè)匹配返回從最后一個(gè)匹配結(jié)束(或者字符串的開頭)到匹配開始的文本。
當(dāng)沒有更多的匹配,返回最后一個(gè)匹配的結(jié)束到字符串的結(jié)束的文本。
flags參數(shù)是一個(gè)選項(xiàng)text字符串,含有0或者更多單字母標(biāo)記來改變函數(shù)行為。
regexp_split_to_table
支持的標(biāo)記描述在Table 9-19。
除了regexp_split_to_array
返回結(jié)果為text數(shù)組,regexp_split_to_array
函數(shù)行為與regexp_split_to_table
相同, 使用語法
regexp_split_to_array
(string,pattern
[,flags])。
參數(shù)與regexp_split_to_table
相同。
一些例子:
SELECT foo FROM regexp_split_to_table('the quick brown fox jumped over the lazy dog', E'\\s+') AS foo; foo -------- the quick brown fox jumped over the lazy dog (9 rows) SELECT regexp_split_to_array('the quick brown fox jumped over the lazy dog', E'\\s+'); regexp_split_to_array ------------------------------------------------ {the,quick,brown,fox,jumped,over,the,lazy,dog} (1 row) SELECT foo FROM regexp_split_to_table('the quick brown fox', E'\\s*') AS foo; foo ----- t h e q u i c k b r o w n f o x (16 rows)
作為最后一個(gè)例子表明,在出現(xiàn)在字符串的開始或結(jié)束
或在緊接一前一后的匹配,正則表達(dá)式分隔函數(shù)忽略零長度匹配,
這樣實(shí)現(xiàn)regexp_matches
嚴(yán)格上來說是違背了的
正則表達(dá)式匹配的定義,但在實(shí)際使用中,通常是最便利的的行為。
如Perl等軟件系統(tǒng),使用了類似的定義。
PostgreSQL的正則表達(dá)式使用 Henry Spencer 寫的一個(gè)包來實(shí)現(xiàn)。 下面的大部分描述都是從他的手冊(cè)頁里逐字拷貝過來的。
正則表達(dá)式(REs),在POSIX1003.2中定義, 它有兩種形式:擴(kuò)展正則表達(dá)式extendedREs或 EREs(基本上就是在egrep里的那些), 基本正則表達(dá)式basicREs或 BREBREs(基本上就是在 eded里的那些)。 PostgreSQL支持這兩種形式,也實(shí)現(xiàn)了一些POSIX 里面沒有的,在 Perl 或Tcl 這樣的語言中得到廣泛應(yīng)用的類似擴(kuò)展。使用了那些非 POSIX 擴(kuò)展的正則表達(dá)式叫 高級(jí)正則表達(dá)式advancedREs或AREs。 AREs幾乎完全是EREs的超集,但是BREs有幾個(gè)符號(hào)上的不兼容(以及更多的限制)。 我們首先描述AREs和EREs形式, 描述那些只適用于AREs的特性,然后描述與BREs的區(qū)別是什么。
Note: PostgreSQL總是初始化一個(gè)遵循ARE規(guī)則的正則表達(dá)式。然而對(duì)于RE模式,可以在 更多限制的ERE或BRE規(guī)則前面,選擇一個(gè)embedded option,描述在Section 9.7.3.4。 這對(duì)于兼容期望完全POSIX1003.2規(guī)則的應(yīng)用程序,是有用的。
一條正則表達(dá)式可以定義為一個(gè)或多個(gè)的分支,由|分隔。 它要匹配其中任何一個(gè)分支。
一個(gè)分支是0或多個(gè)限定的原子quantified atoms或約束constraints連接而成。 一個(gè)原子匹配第一個(gè),后面的原子匹配第二個(gè),依次類推。一個(gè)空的分支要匹配空字符串。
一個(gè)有限定的原子是一個(gè)原子atom,后面可能跟著一個(gè)界定符quantifier。沒有界定符的時(shí)候, 它匹配一個(gè)原子,有界定符的時(shí)候,它可以匹配若干個(gè)原子。 原子的各種可能性,在atom在Table 9-12里面顯示??赡艿慕缍ǚ退麄兊暮x在Table 9-13里顯示。
一個(gè)約束constraint匹配一個(gè)空字符串, 但只是在滿足特定條件下才匹配。約束可以在能夠使用原子的地方使用, 只是它不能跟著界定符。簡單的約束在Table 9-14里顯示;稍后描述更多的約束。
Table 9-12. 正則表達(dá)式原子
原子 | 描述 |
---|---|
(re) | (re是任意正則表達(dá)式)匹配一個(gè)對(duì) re 的匹配,有可報(bào)告的匹配信息。 |
(?:re) | as above, but the match is not noted for reporting (a"non-capturing"set of parentheses) (AREs only) 同上,但是不會(huì)報(bào)告匹配信息(一個(gè)"非捕獲"non-capturing""括號(hào)),只在 ARE 中有。 |
. | 匹配任意單個(gè)字符 |
[chars] | 一個(gè)方括弧表達(dá)式bracket expression,匹配chars中的任意字符 (參閱Section 9.7.3.2獲取更多細(xì)節(jié))。 |
\k | (k是非字母數(shù)字字符)匹配一個(gè)當(dāng)作普通字符看待的特定字符,比如\\匹配一個(gè)反斜杠。 |
\c | c是一個(gè)字母數(shù)字(可能跟著其它字符),首項(xiàng)是逃逸符escape,參閱Section 9.7.3.3。 (僅在ARE 中;在 ERE 和 BRE 中,它匹配c)。 |
{ | when followed by a character other than a digit, matches the left-brace character{; when followed by a digit, it is the beginning of a bound(see below) 如果后面跟著一個(gè)非數(shù)字字符,那么就 匹配左花括弧{;如果跟著一個(gè)數(shù)字,那么它是范圍bound的開始(見下面) |
x | 這里的x是一個(gè)沒有其它特征的單個(gè)字符,則匹配該字符。 |
RE不能以\結(jié)尾。
Note: 要記住反斜杠(\)在PostgreSQL字符串文本中已經(jīng)有特殊含義了。 要寫一個(gè)包含反斜杠的模式,你必須在語句里寫兩個(gè)反斜杠(參閱Section 4.1.2.1)。
Table 9-13. 正則表達(dá)式界定符
界定符 | 匹配 |
---|---|
* | 一個(gè)匹配0或更多個(gè)原子的序列 |
+ | 一個(gè)匹配 1或更多個(gè)原子的序列 |
? | 一個(gè)匹配0或1個(gè)原子的序列 |
{m} | 一個(gè)正好匹配m個(gè)原子的序列 |
{m,} | 一個(gè)匹配m個(gè)或者更多原子的序列 |
{m,n} | 一個(gè)匹配m到n個(gè)(包含兩端)原子的序列;m不能比n大 |
*? | *的非貪婪模式 |
+? | +的非貪婪模式 |
?? | ?的非貪婪模式 |
{m}? | {m}的非貪婪模式 |
{m,}? | {m,}的非貪婪模式 |
{m,n}? | {m,n}的非貪婪模式 |
{...}的形式被稱作范圍bounds。 一個(gè)范圍內(nèi)的數(shù)字m和n都是無符號(hào)十進(jìn)制整數(shù),允許的數(shù)值從 0 到 255 (閉區(qū)間)。
Non-greedy界定符(只在 ARE 中可用)匹配對(duì)應(yīng)的正常(greedy)模式, 區(qū)別是它尋找最少的匹配,而不是最多的匹配。參閱Section 9.7.3.5獲取更多細(xì)節(jié)。
Note: 一個(gè)界定符不能緊跟在另外一個(gè)界定符后面。例如,**是無效的。界定符不能是表達(dá)式或者子表達(dá)式的開頭, 也不能跟在^或|后面。
Table 9-14. 正則表達(dá)式約束
約束 | 描述 |
---|---|
^ | 匹配字符串的開頭 |
$ | 匹配字符串的結(jié)尾 |
正向預(yù)查positive lookahead在任何匹配re的字符串開始處匹配查找字符串(只在 ARE 中有)。 | ? |
(?!re) | 負(fù)向預(yù)查negative lookahead在任何不匹配re的字符串開始處匹配查找字符串(只在 ARE 中有)。 |
預(yù)查約束不能包含后引用back references(參閱Section 9.7.3.3),并且在其中的所有圓括號(hào)都被認(rèn)為是不捕獲的。
方括號(hào)表達(dá)式bracket expression是一個(gè)[]括起來的字符列表。它通常匹配任意單個(gè)列表中的 字符(又見下文)。如果列表以^開頭,它匹配任意單個(gè)不在該列表中的字符。 如果該列表中兩個(gè)字符用-隔開,那它就是那兩個(gè)字符(包括在內(nèi))之間的所有字符范圍的縮寫, 比如,在ASCII里[0-9]匹配查找任何十進(jìn)制數(shù)字。兩個(gè)范圍共享一個(gè)終點(diǎn)是非法的, 比如a-c-e。這個(gè)范圍與序列順序關(guān)系密切,可移植的程序不應(yīng)該依靠它們。
在列表中包含文本],可以讓它做列表的首字符(可能會(huì)在一個(gè)^后面)。 在列表中包含文本-,可以讓它做列表的首字符或者末字符,或者一個(gè)范圍的第二個(gè)終點(diǎn)。 在列表中把文本-當(dāng)做范圍的起點(diǎn),把它用[.and.]包圍起來,這樣它就成為一個(gè) 集合元素(見下文)。除了這些字符本身,和一些用[的組合(見下段), 以及逃逸(只在 ARE 中有效)以外,所有其它特殊字符在方括弧表達(dá)式里都失去它們的特殊含義。 特別是,在 ERE 和 BRE 規(guī)則下\不是特殊的,但在 ARE 里,它是特殊的(還是引入一個(gè)逃逸)。
在一個(gè)方括弧表達(dá)式里,一個(gè)集合元素(一個(gè)字符、一個(gè)當(dāng)做一個(gè)字符的多字符序列、或者 一個(gè)表示上面兩種情況的集合序列)包含在[.和.]里面的時(shí)候表示該集合元素的字符序列。 該序列是該方括弧列表的一個(gè)元素。因此一個(gè)包含多字符集合元素的方括弧表達(dá)式就可以 匹配多于一個(gè)字符,比如,如果集合序列包含一個(gè)ch集合元素,那么[[.ch.]]*c 匹配chchcc的頭五個(gè)字符。 譯注:其實(shí)把 [. 和 .] 括起來的整體當(dāng)一個(gè)字符看就行了。
Note: PostgreSQL目前不支持多字節(jié)符集合元素。這些信息描述了將來可能有的行為。
在方括弧表達(dá)式里,在[=和=]括起來的集合元素是一個(gè)等價(jià)表, 代表等于這里所有集合元素的字符序列,包括它本身(如果沒有其它等效集合元素, 那么就處理如同由[.和.].)的界定符。例如, 如果o和^是一個(gè)等價(jià)類的成員, 那么[[=o=]],[[=^=]],[o^]都是同義的。一個(gè)等價(jià)表不能是一個(gè)范圍的端點(diǎn)。
在方括弧表達(dá)式里,在[:和:]里面括起來的字符表名,代表屬于該表的所有字符的列表。 標(biāo)準(zhǔn)的字符表名字是:alnum, alpha,blank, cntrl,digit, graph,lower, print,punct, space,upper, xdigit。它們代表 在ctype里定義的字符表。 本地化設(shè)置可能會(huì)提供其它的表。字符表不能用做一個(gè)范圍的端點(diǎn)。
在方括弧表達(dá)式里有兩個(gè)特例:方括弧表達(dá)式[[:<:]]和[[:>:]]是約束, 分別匹配一個(gè)單詞開頭和結(jié)束的空串。單詞定義為一個(gè)單詞字符序列,前面和后面 都沒有其它單詞字符。單詞字符是一個(gè)alnum字符(和ctype) 里定義的一樣)或者一個(gè)下劃線。這是一個(gè)擴(kuò)展,兼容POSIX1003.2 ,但那里面并沒有說明,而且在準(zhǔn)備移植到其它系統(tǒng)里去的軟件里一定要小心使用。 通常下面描述的約束逃逸更好些(他們并非更標(biāo)準(zhǔn),但是肯定更容易輸入)。
Escapes是以\開頭,后面跟著一個(gè)字母數(shù)字字符的特殊序列。逃逸有好幾種 變體:字符項(xiàng)、表縮寫、約束逃逸、后引用。在 ARE 里,如果一個(gè)\后面跟著一個(gè) 字母數(shù)字,但是并未組成一個(gè)合法的逃逸,那么它是非法的。在 ERE 里則沒有逃逸:在 方括弧表達(dá)式之外,一個(gè)跟著字母數(shù)字字符的\只是表示該字符是一個(gè)普通字符, 而在一個(gè)方括弧表達(dá)式里,\是一個(gè)普通的字符(后者實(shí)際上是 ERE 和 ARE 之間的不兼容)。
字符項(xiàng)逃逸Character-entry escapes用于方便我們聲明正則表達(dá)式里那些不可打印和在RE里其它不方便的字符。 它們?cè)赥able 9-15里列出。
類縮寫逃逸Class-shorthand escapes用來提供一些常用的字符類縮寫。他們?cè)赥able 9-16里列出
約束逃逸constraint escape是一個(gè)約束,如果滿足特定的條件,它匹配該空字符串,作為逃逸編寫。 它們?cè)赥able 9-17里列出。
后引用back reference(\n)匹配數(shù)字n 指定前面圓括弧子表達(dá)式匹配的同一個(gè)字符串(參閱Table 9-18)。 例如,(([bc])\1匹配bb或cc但是不匹配bc或cb。 正則表達(dá)式里的子表達(dá)式必須完全在后引用前面。非捕獲圓括弧并不定義子表達(dá)式。
Note: 請(qǐng)記住,如果把模式當(dāng)作一個(gè) SQL 字符串常量輸入,那么逃逸前導(dǎo)的\需要雙倍地寫。例如:
'123' ~ E'^\\d{3}'true
Table 9-15. 正則表達(dá)式字符項(xiàng)逃逸
逃逸 | 描述 |
---|---|
\a | 警笛(鈴聲)字符,和 C 里一樣 |
\b | 退格,和 C 里一樣 |
\B | \的同義詞,用于減少反斜杠加倍的需要 |
\cX | (這里X是任意字符)字符的低5位和X里的相同,其它位都是0。 |
\e | 集合序列名字是ESC的字符,如果不是,則是八進(jìn)制值為033的字符 |
\f | 進(jìn)紙,和C里一樣 |
\n | 新行,和C里一樣 |
\r | 回車,和C里一樣 |
\t | 水平制表符,和C里一樣 |
\uwxyz | (這里的wxyz是恰好四個(gè)十六進(jìn)制數(shù)字)本機(jī)字節(jié)序的 UTF-16(寬字符,16位)字符U+wxyz。 |
\Ustuvwxyz | (wherestuvwxyzis exactly eight hexadecimal digits) reserved for a hypothetical Unicode extension to 32 bits (這里的stuvwxyz是恰好八個(gè)十六進(jìn)制數(shù)字)為Unicode 32 位擴(kuò)展預(yù)留的。 |
\v | 垂直制表符,和 C 里一樣 |
\xhhh | (這里的hhh是一個(gè)十六進(jìn)制序列)十六進(jìn)制 值為0xhhh的字符(不管用了幾個(gè)十六進(jìn)制位,都是一個(gè)字符)。 |
\0 | 值為0的字符(空字節(jié)) |
\xy | (這里的xy是恰好兩個(gè)八進(jìn)制數(shù)字,并且不是一個(gè)back reference后引用)八進(jìn)制值為0xy的字符 |
\xyz | (這里的xyz是恰好三位八進(jìn)制位,并且不是一個(gè) 后引用)八進(jìn)制值為0xyz的字符 |
十六進(jìn)制數(shù)字是0-9,a-f,A-F。八進(jìn)制數(shù)字是0-7。
字符項(xiàng)逃逸總是被當(dāng)作普通字符。例如,\135是 ASCII 中的], 但\135并不結(jié)束一個(gè)方括弧表達(dá)式。
Table 9-16. 正則表達(dá)式類縮寫逃逸
逃逸 | 描述 |
---|---|
\d | [[:digit:]] |
\s | [[:space:]] |
\w | [[:alnum:]_] (注意,這里是包含下劃線的) |
\D | [^[:digit:]] |
\S | [^[:space:]] |
\W | [^[:alnum:]_] (注意,這里是包含下劃線的) |
在方括號(hào)表達(dá)式里,\d,\s, \w會(huì)失去他們的外層方括號(hào),而\D,\S,\W是非法的。 比如[a-c\d]等效于[a-c[:digit:]]。 同樣[a-c\D]原來等效于[a-c^[:digit:]]的,也是非法的。
Table 9-17. 正則表達(dá)式約束逃逸
逃逸 | 描述 |
---|---|
\A | 只匹配字符串開頭(參閱Section 9.7.3.5獲取它和^區(qū)別的信息) |
\m | 只匹配一個(gè)詞的開頭 |
\M | 只匹配一個(gè)詞的結(jié)尾 |
\y | 只匹配一個(gè)詞的開頭或者結(jié)尾 |
\Y | 只匹配那些既不是詞的開頭也不是詞的結(jié)尾的點(diǎn) |
\Z | 只匹配一個(gè)字符串的結(jié)尾(參閱Section 9.7.3.5獲取它和$區(qū)別的信息) |
一個(gè)詞的定義是上面[[:<:]]和[[:>:]]的聲明。 在方括弧表達(dá)式里,約束逃逸是非法的。
Table 9-18. 正則表達(dá)式后引用
逃逸 | 描述 |
---|---|
\m | 這里的m是一個(gè)非零數(shù)字)一個(gè)指向第m個(gè)子表達(dá)式的后引用 |
\mnn | (這里的m是一個(gè)非零數(shù)字,nn是更多的數(shù)字,并且十進(jìn)制數(shù)值mnn 不能大于到這個(gè)位置為止的閉合捕獲圓括號(hào)的個(gè)數(shù))一個(gè)指向第 mnn 個(gè)子表達(dá)式的后引用。 |
Note: 在八進(jìn)制字符項(xiàng)逃逸和后引用之間有一個(gè)歷史繼承的歧義存在,這個(gè)歧義是 通過啟發(fā)分析解決的,像上面描述的那樣。前導(dǎo)零總是表示這是一個(gè)八進(jìn)制逃逸。 而單個(gè)非零數(shù)字,如果沒有跟著任何其它數(shù)字,那么總是認(rèn)為是后引用。 一個(gè)多數(shù)據(jù)位的非零開頭的序列也認(rèn)為是后引用(只要它在合適的子表達(dá)式后面, 也就是說,數(shù)值在后引用的合法范圍內(nèi)),否則就認(rèn)為是一個(gè)八進(jìn)制。
除了上面描述的主要語法之外,還有幾種特殊形式和雜項(xiàng)語法。
正則表達(dá)式可以用兩個(gè)特殊意義的director前綴其中之一。 如果一個(gè)正則表達(dá)式以***:開頭,正則表達(dá)式其余部分,可以作為ARE。 (在正則表達(dá)式作為ARE后,這通常在PostgreSQL沒有影響的;但是 如果在ERE或BRE模式指定一個(gè)flags參數(shù)給正則表達(dá)式函數(shù),確實(shí)是有影響的。) 如果一個(gè)正則表達(dá)式以***=開頭,正則表達(dá)式其余部分作為文本字符串, 所有字符串視為普通字符。
ARE可以用embedded options開頭;一個(gè)序列(?xyz) (這里xyz是1個(gè)或更多個(gè)字母字符)特定的選項(xiàng)影響正則表達(dá)式的其余部分。 這些選項(xiàng)覆蓋任何先前確定的選項(xiàng) —尤其,他們可以覆蓋正則表達(dá)式操作符或flags 給正則表達(dá)式函數(shù)的隱含區(qū)分大小寫的行為。可用的字母選項(xiàng)顯示在Table 9-19。 注意同樣這些字母選項(xiàng)可以用作正則表達(dá)式函數(shù)的flags參數(shù)。
Table 9-19. ARE 嵌入選項(xiàng)字母
選項(xiàng) | 描述 |
---|---|
b | 正則表達(dá)式的其余部分是BRE |
c | 大小寫敏感匹配(覆蓋操作符類型) |
e | 正則表達(dá)式的其余部分是 ERE |
i | 大小寫不敏感匹配(參閱Section 9.7.3.5)(覆蓋操作符類型) |
m | n的歷史同義詞 |
n | 換行敏感匹配(參閱Section 9.7.3.5) |
p | 部分換行敏感匹配(參閱Section 9.7.3.5) |
q | 正則表達(dá)式的其余部分為一個(gè)文本("quoted")字符串,所有都是普通字符 |
s | 非換行敏感匹配(缺省) |
t | 嚴(yán)格的語法(缺省,見下文) |
w | 反部分換行敏感("怪異""weird")匹配(參閱Section 9.7.3.5) |
x | 擴(kuò)展的語法(見下文) |
嵌入的選項(xiàng)在終止其序列的)發(fā)生作用。他們只在 ARE 的開始處起作用(即在任何***:引導(dǎo)符后面)。
除了通常情況下所有的選項(xiàng)字符都顯然遵循(嚴(yán)格tight)正則表達(dá)式語法,還有 一種擴(kuò)展expanded語法,可以通過聲明嵌入的x選項(xiàng)使用。在擴(kuò)展語法里, 正則表達(dá)式中的空白字符被忽略,就像那些在#和新行后(或正則表達(dá)式的結(jié)尾處)之間的所有字符一樣。這樣就允許 我們給一個(gè)復(fù)雜的正則表達(dá)式分段和注釋。不過這個(gè)基本規(guī)則上有三種例外:
前置了\的空白符或#保留
在方括號(hào)表達(dá)式里的空白符或者#保留
在多個(gè)字符符號(hào)里面不能出現(xiàn)空白和注釋,比如(?:。
在這里,空白是空白、水平制表符、換行、和任何屬于space(空白)字符表的字符。
最后,在 ARE 里,方括號(hào)表達(dá)式外面,序列(?#ttt)(這里的ttt是任意不包含) 的文本)是一個(gè)注釋,完全忽略掉。再次,在多字符符號(hào)里,不允許使用,例如(?:。這樣的注釋是比一個(gè)有用的工具更歷史些, 他們的用法已經(jīng)廢棄了;我們應(yīng)該使用擴(kuò)展語法代替他。
如果聲明了一個(gè)初始化的***=引導(dǎo)符,那么所有這些元語法擴(kuò)展都不能使用, 因?yàn)檫@樣表示把用戶輸入當(dāng)作一個(gè)文本字符串而不是正則表達(dá)式對(duì)待。
在正則表達(dá)式可以匹配給出的字符串中多于一個(gè)子串的情況下,正則表達(dá)式 匹配字符串中最早開始匹配的那個(gè)子串。如果正則表達(dá)式可以匹配多個(gè)子串在那些位置開始處,要么是匹配最長的, 要么是最短的,具體哪種,取決于正則表達(dá)式是貪婪greedy的還是非貪婪non-greedy的。
一個(gè)正則表達(dá)式是否貪婪取決于下面規(guī)則:
大多數(shù)原子,以及所有約束,都沒有貪婪屬性(因?yàn)樗鼈儺吘篃o法匹配變量的文本)。
在一個(gè)正則表達(dá)式周圍加上圓括號(hào)并不會(huì)改變其貪婪性。
一個(gè)帶有固定重復(fù)次數(shù)的界定符(({m}或 {m}?)的量化原子和原子自身有著同樣的貪婪性(可能是沒有)。
一個(gè)帶其它普通的量詞(包括{m,n}中 m等于n的情況)量化的原子是貪婪的(首選最長匹配)。
一個(gè)帶非貪婪量詞(包括{m,n}? 中m等于n的情況)量化原子是非貪婪的(首選最短匹配)。
一個(gè)分支(也就是一個(gè)沒有頂級(jí)|操作符的 正則表達(dá)式)和它里面的第一個(gè)有貪婪屬性的量化原子有著同樣的貪婪性。
一個(gè)由|操作符連接起來的兩個(gè)或者更多分支組成的正則表達(dá)式總是貪婪的。
上面的規(guī)則所描述的貪婪屬性不僅僅適用于獨(dú)立的量化原子,而且也適用于 包含量化原子的分支和整個(gè)正則表達(dá)式。這里的意思是,匹配是按照分支或者整個(gè) 正則表達(dá)式作為一個(gè)整體匹配最長或者最短的子字符串的可能。一旦整個(gè) 匹配的長度確定,那么匹配任意子表達(dá)式的部分就基于該子表達(dá)式的貪婪屬性進(jìn)行判斷, 在正則表達(dá)式里面靠前的子表達(dá)式的優(yōu)先級(jí)高于靠后的子表達(dá)式。
一個(gè)表達(dá)這些意思的例子:
SELECT SUBSTRING('XY1234Z', 'Y*([0-9]{1,3})'); Result:123 SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})'); Result:1
在第一個(gè)例子里,正則表達(dá)式作為整體是貪婪的,因?yàn)?tt class="LITERAL">Y*是貪婪的。 它可以匹配從Y開始的東西,并且它匹配從這個(gè)位置開始的最長的字符串, 也就是Y123。輸出是這里的圓括弧包圍的部分,或者說是123。在第二個(gè)例子里, 正則表達(dá)式總體上是一個(gè)非貪婪的正則表達(dá)式 ,因?yàn)?tt class="LITERAL">Y*?是非貪婪的。它可以匹配 從Y開始的最短的子字符串,也就是說Y1。子表達(dá)式[0-9]{1,3}是貪婪的, 但是它不能修改總體匹配長度的決定;因此它被迫只匹配1。
簡單說,如果一個(gè)正則表達(dá)式同時(shí)包含貪婪和非貪婪的子表達(dá)式,那么總匹配長度要么是最長可能,要么是最短可能, 取決于給整個(gè)正則表達(dá)式賦予的貪婪屬性。給子表達(dá)式賦予的貪婪屬性只影響在這個(gè)匹配里, 各個(gè)子表達(dá)式之間相互允許"吃進(jìn)"eat""的多少。
量詞{1,1}和{1,1}?可以分別用于在一個(gè)子表達(dá)式或者整個(gè)正則表達(dá)式上強(qiáng)制貪婪或者非貪婪。
匹配長度是以字符衡量的,而不是集合的元素。一個(gè)空字符串會(huì)被認(rèn)為 比什么都不匹配長。比如:bb*匹配abbbc的中間三個(gè)字符; (week|wee)(night|knights)匹配weeknights的所有十個(gè)字符; 而(.*).*匹配abc的時(shí)候,圓括號(hào)包圍的子表達(dá)式匹配所有三個(gè)字符; 而如果用(a*)*匹配bc,那么整個(gè)正則表達(dá)式和圓括號(hào)子表達(dá)式都匹配一個(gè)空字符串。
如果聲明了大小寫無關(guān)的匹配,那么效果就好像把所有字母上的大小寫區(qū)別 取消了一樣。如果一個(gè)存在大小寫差別的字母以一個(gè)普通字符的形式出現(xiàn)在方括弧 表達(dá)式外面,那么它實(shí)際上被轉(zhuǎn)換成一個(gè)包含大小寫的方括弧表達(dá)式,也就是說, x變成[xX]。如果它出現(xiàn)在一個(gè)方括弧表達(dá)式里面,那么它的所有大小寫的同族都被加入 方括弧表達(dá)式中,也就是說,[x]變成[xX]而[^x]變成[^xX]。
如果聲明了換行敏感匹配,.和使用^的方括弧表達(dá)式將永遠(yuǎn)不會(huì)匹配換行字 符(這樣,匹配就絕對(duì)不會(huì)跨換行,除非正則表達(dá)式明確地指定了這樣的情況)并 且^和$除了分別匹配字符串開頭和結(jié)尾之外,還將分別匹配換行后面和前面的 空字符串。但是 ARE 逃逸\A和\Z仍然只配字符串的開頭和結(jié)尾。
如果聲明了部分換行敏感匹配,那么它影響.和 方括弧表達(dá)式,這個(gè)時(shí)候和換行敏感匹配一樣,但是不影響^和$.。
如果聲明了反轉(zhuǎn)換行敏感匹配,那么它影響^和$,作用和換行敏感匹配里一樣, 但是不影響.和方括號(hào)表達(dá)式。這個(gè)沒什么太多用途,只是為了對(duì)稱提供的。
在這個(gè)實(shí)現(xiàn)里,對(duì)正則表達(dá)式的長度沒有特別的限制,但是,那些希望能夠有很好移植行的程序應(yīng)該避免寫超 過 256 字節(jié)的正則表達(dá)式 ,因?yàn)?POSIX 兼容的實(shí)現(xiàn)可以拒絕接受這樣的正則表達(dá)式。
ARE 實(shí)際上和 POSIX ERE 不兼容的唯一的特性是在方括號(hào)表達(dá)式里\ 并不失去它特殊的含義。所有其它 ARE 特性都使用在 POSIX ERE 里面是非法或者是未定義、 未聲明效果的語法;引導(dǎo)符的***就是再 POSIX 的 BRE 和 ERE 之外的語法。
許多 ARE 擴(kuò)展都是從 Perl 那里拿來的,但是有些做了修改,去掉了, 以及一些 Perl 里沒有出現(xiàn)的擴(kuò)展。要注意的不兼容包括\b,\B,對(duì)結(jié)尾的換行 缺乏特別的處理,對(duì)那些換行敏感匹配的附加的補(bǔ)齊方括弧表達(dá)式,在前瞻約束里 對(duì)圓括號(hào)和方括號(hào)引用的限制,以及最長/最短匹配(而不是第一匹配)語義。
PostgreSQL 7.4 之前的版本里的 ARE 和 ERE 存在兩個(gè)非常顯然的不兼容:
在 ARE 里,后面跟著一個(gè)字母數(shù)字的\要么是一個(gè)逃逸,要么是錯(cuò)誤,但是在以前的版本里, 它只是寫那個(gè)字母數(shù)字的另外一種方法。這個(gè)應(yīng)該不是什么問題,因?yàn)樵谝郧暗陌姹纠餂]有什么原因讓我們寫這樣的序列。
在 ARE 里\在[]里還是一個(gè)特殊字符, 因此在方括號(hào)表達(dá)式里的一個(gè)文本\必須寫成\\。
BRE 在幾個(gè)方面和 ERE 不太一樣。|,+,?都是普通字符,它們沒有等效的功能替換。 范圍的分隔符是\{和\},因?yàn)?tt class="LITERAL">{和}本身是普通字符。 嵌套的子表達(dá)式的圓括號(hào)是\(和\),因?yàn)?tt class="LITERAL">(和)自身是普通字符。 除非在正則表達(dá)式開頭或者是圓括號(hào)封裝的子表達(dá)式開頭,^都是普通字符, 除非在正則表達(dá)式結(jié)尾或者是圓括號(hào)封裝的子表達(dá)式的結(jié)尾,$是一個(gè)普通字符, 而如果*出現(xiàn)在正則表達(dá)式開頭或者是圓括號(hào)封裝的子表達(dá)式開頭(前面可能有^), 那么它是個(gè)普通字符。最后,可以用單數(shù)字的后引用,以及\<和\>分別 是[[:<:]]和[[:>:]]的同義詞;沒有其它的逃逸。