9.7. 模式匹配

PostgreSQL 提供了三種實現模式匹配 的方法:SQL LIKE 操作符,更近一些的 SIMILAR TO 操作符(SQL:1999 裡添加進來的), 和POSIX-風格正則資料表達式。 另外還有一個模式匹配函數 substring 可以用, 它可以使用 SIMILAR TO 風格的或者 POSIX 風格的正則資料表達式。

提示: 如果您的模式匹配的要求比這些還多,或者想寫一些模式驅動的 替換和轉換,請考慮用 Perl 或 Tcl 寫一個用戶定義函數。

9.7.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 子句指定一個。 要匹配逃逸字元本身,寫兩個逃逸字元。

請注意反斜槓在字串文本裡已經有特殊含義了,所以如果您寫一個 包含反斜槓的模式常量,那您就要在 SQL 語句裡寫兩個反斜槓。 因此,寫一個匹配單個反斜槓的模式實際上要在語句裡寫四個反斜槓。 您可以透過用 ESCAPE 選擇一個不同的逃逸字元 來避免這樣;這樣反斜槓就不再是 LIKE 的特殊字元了。 但仍然是字元文本分析器的特殊字元,所以您還是需要兩個反斜槓。)

我們也可以透過寫成 ESCAPE '' 的方式 有效地關閉逃逸機制,這時,我們就不能關閉下劃線和百分號的特殊含義。

關鍵字 ILIKE 可以用於替換 LIKE, 令該匹配就目前的區域設置是大小寫無關的。 這個特性不是 SQL 標準,是 PostgreSQL 擴展。

操作符 ~~ 等效於 LIKE, 而 ~~* 對應 ILIKE。 還有 !~~!~~* 操作符 分別代資料表 NOT LIKENOT ILIKE。所有這些操作符都是 PostgreSQL 特有的。

9.7.2. SIMILAR TO 正則資料表達式

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

SIMILAR TO 根據自己的模式是否匹配給定字串而返回真或者假。 它和 LIKE 非常類似,只不過它使用 SQL 標準定義的正則資料表達式理解模式。 SQL 標準的正則資料表達式是在 LIKE 資料表示法和普通的正則資料表達式資料表示法之間古怪的交叉。

類似 LIKESIMILAR TO 操作符只有在它的模式匹配整個字串的時候才能成功;這一點和普通的 正則資料表達式的習慣不同,在普通的正則資料表達式裡,模式匹配字串的任意 部分。 和 LIKE 類似的地方還有,SIMILAR TO 使用 _% 作為分別代資料表任意字串和任意字串字元 的通配符。(這些和 POSIX 正則資料表達式裡的 ..* 兼容)

除了這些從 LIKE 借用的功能之外, SIMILAR TO 支援下面這些從 POSIX 正則資料表達式借用的 模式匹配元字元:

請注意沒有提供範圍重複(?{...}), 儘管它們在 POSIX 裡有。同時,點(.)不是元字元。

LIKE 一樣,反斜槓關閉所有這些元字元的特殊含義; 當然我們也可以用 ESCAPE 聲明另外一個逃逸字元。

一些例子:

'abc' SIMILAR TO 'abc'      true
'abc' SIMILAR TO 'a'	false
'abc' SIMILAR TO '%(b|d)%'  true
'abc' SIMILAR TO '(b|c)%'   false

帶三個參數的substringsubstring(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.7.3. POSIX 正則資料表達式

Table 9-11 列出了所有可用的 用於 POSIX 正則資料表達式的操作符。

Table 9-11. 正則資料表達式匹配操作符

操作符描述例子
~ 匹配正則資料表達式,大小寫相關'thomas' ~ '.*thomas.*'
~* 匹配正則資料表達式,大小寫無關'thomas' ~* '.*Thomas.*'
!~ 不匹配正則資料表達式,大小寫相關'thomas' !~ '.*Thomas.*'
!~* 不匹配正則資料表達式,大小寫無關'thomas' !~* '.*vadim.*'

POSIX 正則資料表達式提供了比 LIKESIMILAR TO 操作符 更強大的模式匹配的方法。許多 Unix 工具,比如 egrepsed,或 awk 使用一種與我們這裡描述的類似的模式匹配語言。

正則資料表達式是一個字元序列,它是定義一個字串集合 (一個正則集合)的縮寫。 如果一個字串是正則資料表達式描述的正則集合中的一員時, 我們就說這個字串匹配該正則資料表達式。 和 LIKE 一樣,模式字元準確地匹配字串字元, 除非在正則資料表達式語言裡有特殊字元 — 不過正則資料表達式用的 特殊字元和 LIKE 用的不同。 和 LIKE 不一樣的是,正則資料表達式 可以匹配字串裡的任何位置,除非該正則資料表達式明確地掛接在字串 的開頭或者結尾。

一些例子:

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

帶兩個參數的substringsubstring(string from pattern),提供了從字串中抽取一個匹配 POSIX 正則資料表達式模式的 子字串的方法。如果沒有匹配它返回 NULL,否則就是文本中匹配模式的那部分。 但是如果該模式包含任何圓括弧,那麼將返回匹配第一對子資料表達式(對應第一個左圓括弧的) 的文本。如果您想在資料表達式裡使用圓括弧而又不想導致這個例外,那麼您可以在整個資料表達式外邊放上一對兒圓括弧。 如果您需要在想抽取的子資料表達式前有圓括弧,參閱描述的非捕獲性圓括弧。

一些例子:

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

PostgreSQL 的正則資料表達式是使用 Henry Spencer 寫的一個包來實現的。下面的正則資料表達式的大部分描述都是從他的手冊頁裡面 逐字拷貝過來的。

9.7.3.1. 正則資料表達式

正則資料表達式("RE"),在POSIX1003.2 中定義, 它有兩種形式:擴展的RE或者是ERE (基本上就是那些在 egrep 裡的), "基本"RE或者是BRE (基本上就是那些在 ed裡的)。 PostgreSQL 兩種形式都實現了,並且還做了一些POSIX裡面沒有的, 但是因為在類似 Perl 或者 Tcl 這樣的語言中得到廣泛應用的一些擴展。 使用了那些非POSIX擴展的 RE高級 RE, 或者我們文件裡說的 ARE。ARE 幾乎完全是 ERE 的超集,但是 BRE 有幾個符號上的不兼容(以及更多的限制)。我們首先描述 ARE 和 ERE 形式, 描述那些只適用於 ARE 的特性,然後描述 BRE 的區別是什麼。

注意: 我們可以透過設置執行時參數regex_flavor來選擇 PostgreSQL 接受的正則資料表達式的形式。 通常的設置是advanced(高級),但是我們可以選擇 extended 和 7.4 以前的PostgreSQL版本做到最大的向下兼容。

(現代)的 RE 是一個或多個非空的 分支, 由 | 分隔。它匹配任何匹配其中一個分支的東西。

一個分支是一個或多個有修飾的原子或者約束 連接而成。一個原子匹配第一個,然後後面的原子匹配第二個, 以此類推。

一個有修飾的原子是一個原子, 後面可能跟著一個量詞。沒有量詞的時候,它匹配一個原子, 有量詞的時候,它可以匹配若干個原子。原子可以是在 Table 9-12裡面顯示的任何可能。 可能的量詞和他們的含義在 Table 9-13 裡顯示。

一個 constraint 匹配一個空字串,但只是在滿足特定條件下才匹配。 約束可以在能夠使用原子的地方使用,只是她不能跟著量詞。最簡單的原子在 Table 9-14 裡顯示; 更多的約束稍後描述。

Table 9-12. 正則資料表達式原子

原子描述
(re) (這裡的 re 是任何正則資料表達式) 匹配一個對 re 的匹配,有可報告的匹配訊息
(?:re) 同上,但是匹配不會被報告 (一個"不捕獲"圓括弧) (只在 ARE 中有)
. 匹配任意單個字元
[chars] 一個 方括弧資料表達式, 匹配任意的字元(參閱 Section 9.7.3.2 獲取更多細節)
\k (這裡的 k 是非字母數字字元) 匹配一個當作普通字元看待的特定字元, 比如,\\ 匹配一個反斜槓
\c 這裡的 c 是一個字母數字 (可能跟著其它字元),它是一個逃逸, 參閱 Section 9.7.3.3(僅存在於 ARE; 在 ERE 和 BRE 中,它匹配 c
{ 如果後面跟著一個字元,而不是數字, 那麼就匹配左花括弧{;如果跟著一個數字, 那麼它是範圍的開始(見下面)
x 這裡的 x 是一個沒有其它特徵的單個字元, 則匹配該字元

RE 不能以 \ 結尾。

注意: 要記住反斜槓(\)在 PostgreSQL 字串文本中已經有特殊含義了。 要寫一個包含反斜槓的模式,您必須在語句裡寫兩個反斜槓。比如:

'123' ~ '^\\d{3}' true

Table 9-13. 正則資料表達式量詞

量詞匹配
* 一個匹配 0 或者更多個原子的序列
+ 一個匹配 1 或者更多個原子的序列
? 一個匹配 0 個或者 1 個原子的序列
{m} 一個正好匹配 m 個原子的序列
{m,} 一個匹配m 個或者更多原子的序列
{m,n} 一個匹配 mn 個(包含兩端) 原子的序列;m 不能比 n
*? * 的非貪婪模式
+? + 的非貪婪模式
?? ? 的非貪婪模式
{m}? {m} 的非貪婪模式
{m,}? {m,} 的非貪婪模式
{m,n}? {m,n} 的非貪婪模式

{...} 的形式被稱作範圍。 一個範圍內的數字 mn 都是無符號十進制整數, 允許的數值從 0 到 255(閉區間)。

非貪婪的量詞(只在 ARE 中可用)匹配對應的正常 (貪婪)模式,區別是它尋找最少的匹配,而不是最多的匹配。 參閱 Section 9.7.3.5 獲取細節。

注意: 一個量詞不能緊跟在另外一個量詞後面。量詞不能是資料表達式或者子資料表達式的開頭, 也不能跟在 ^ 或者 | 後面。

Table 9-14. 正則資料表達式約束

約束描述
^ 匹配字串的開頭
$ 匹配字串的結尾
(?=re) 正前瞻 匹配任何匹配 re 的 子字串起始點(只在 ARE 中有)
(?!re) 負前瞻 匹配任何不匹配 re 的子字串的起始點。(只在 ARE 中有)

前瞻約束不能包含後引用 (參閱 Section 9.7.3.3),並且在裡面的所有圓括弧 都被認為是不捕獲的。

9.7.3.2. 方括弧資料表達式

方括弧資料表達式是一個包圍在 [] 裡的字元列資料表。它通常匹配任意單個 列資料表中的字元(又見下文)。 如果列資料表以 ^ 開頭,它匹配 任意單個(又見下文)不在該列資料表中的字元。 如果該列資料表中兩個字元用-隔開, 那它就是那兩個字元(包括在內)之間的所有字元範圍的縮寫, 比如,在 ASCII[0-9] 包含任何十進制數字。 兩個範圍共享一個終點是非法的,比如, a-c-e。這個範圍與字元集關係密切, 可移植的程序不應該依靠它們。

想在列資料表中包含文本 ],可以讓它做 列資料表的首字元(可能會在一個 ^ 後面)。 想在列資料表中包含文本 -,可以讓它做 列資料表的首字元或者末字元,或者一個範圍的第二個終點。 想在列資料表中把文本-當做範圍的起點, 把它用 [..] 包圍起來,這樣它就成為一個集合元素(見下文)。 除了這些字元本身,和一些用 [ 的組合(見下段),以及逃逸(只在 ARE 中有效)以外,所有其它特殊字元 在方括弧資料表達式裡都失去它們的特殊含義。 特別是,在 ERE 和 BRE 規則下 \ 不是特殊的, 但在 ARE 裡,它是特殊的(還是引入一個逃逸)。

在一個方括弧資料表達式裡,一個集合元素(一個字元,一個當做 一個字元的多字元序列,或者一個資料表示上面兩種情況的集合序列) 包含在 [..] 裡面的時候資料表示該集合元素的字元序列。該序列是該方括弧列資料表 的一個元素。因此一個包含多字元集合元素的方括弧資料表達式就 可以匹配多於一個字元,比如,如果集合序列包含一個 ch 集合元素, 那麼 RE [[.ch.]]*c 匹配 chchcc 的頭五個字元。 (譯註:其實把 [. 和 .] 括起來的當一個字元看就行了。)

注意: PostgreSQL 目前沒有多字元集合元素。這些訊息描述了將來可能有的行為。

在方括弧資料表達式裡,在[==] 裡包圍的集合元素是一個等效資料表, 代資料表等於這裡所有集合元素的字元序列,包括它本身。 (如果沒有其它等效集合元素,那麼就好像封裝元素是 [..]。) 比如,如果 o^ 是一個等效資料表的成員,那麼 [[=o=]][[=^=]],和 [o^] 都是同義的。一個等效資料表不能是一個範圍的 端點。

在方括弧資料表達式裡,在 [::] 裡面封裝的字元資料表名字代資料表 屬於該資料表的所有字元的列資料表。 標準的字元資料表名字是:alnumalphablankcntrldigitgraphlowerprintpunctspaceupperxdigit。 它們代資料表在 ctype 裡定義的字元資料表。 本地化設置可能會提供其他的資料表。字元資料表不能用做一個範圍的端點。

在方括弧資料表達式裡有兩個特例:方括弧資料表達式 [[:<:]][[:>:]] 是約束,分別匹配一個單詞開頭和結束的空串。 單詞定義為一個單詞字元序列,前面和後面都沒有其它單詞字元。 單詞字元是一個字母數字(和 ctype 裡定義的一樣) 或者一個下劃線。這是一個擴展,兼容POSIX1003.2, 但那裡面並沒有說明, 而且在準備移植到其他系統裡去的軟件裡一定要小心使用。 通常下面描述的約束逃逸更好些(他們並非更標準,但是肯定更容易敲入)。

9.7.3.3. 正則資料表達式逃逸

逃逸是以 \ 開頭,後面跟著一個字母數字字元得特殊序列。 逃逸有好幾種變體:字元項,資料表縮寫,約束逃逸,以及後引用。在 ARE 裡, 如果一個 \ 後面跟著一個字母數字,但是並未組成一個合法的逃逸, 那麼它是非法的。在 ERE 裡則沒有逃逸:在方括弧資料表達式之外,一個跟著字母數字字元 的 \ 只是資料表示該字元是一個普通的字元,而在一個方括弧資料表達式裡, \ 是一個普通的字元。(後者實際上是 ERE 和 ARE 之間的不兼容。)

字元項逃逸用於方便我們聲明RE裡那些不可打印的字元。 它們在 Table 9-15 裡列出。

資料表縮寫逃逸用來提供一些常用的字元資料表縮寫。 他們在 Table 9-16 裡顯示。

約束逃逸是一個約束,如果滿足特定的條件, 它匹配該空字串。它們在 Table 9-17 裡顯示。

後引用\n)匹配數字 n 指定的前面的圓括弧子資料表達式匹配的同一個字串 (參閱 Table 9-18)。比如, ([bc])\1匹配bb或者cc, 但是不匹配bc或者cb。RE裡子資料表達式必須完全在後引用前面。 非捕獲圓括弧並不定義子資料表達式。

注意: 請注意,如果把模式當作一個 SQL 字串常量輸入,那麼逃逸前導的 \ 需要成倍地寫。

Table 9-15. 正則資料表達式字元項逃逸

逃逸描述
\a 警笛(鈴聲)字元,和 C 裡一樣
\b 退格,和 C 裡一樣
\B \ 的同義詞,用於減少反斜槓加倍的需要
\cX (這裡 X 是任意字元)字元的 低 5 位和 X 裡的相同,其它位都是 0
\e 集合序列名字是 ESC 的字元, 如果不是,則是八進制值為 033 的字元
\f 進紙,和 C 裡一樣
\n 新行,和 C 裡一樣
\r 回車,和 C 裡一樣
\t 水平製資料表符,和 C 裡一樣
\uwxyz (這裡的 wxyz 和恰好四位十六進制位) 本機字元序的 Unicode 字元 U+wxyz
\Ustuvwxyz (這裡的 stuvwxyz 是恰好八位十六進制位) 為那種假想中的 Unicode 32 位擴展保留的
\v 垂直製資料表符,和 C 裡一樣
\xhhh (這裡 hhh 是一個十六進制序列) 十六進制值為 0xhhh 的字元 (不管用了幾個十六進制位,都是一個字元)
\0 值為 0 的字元
\xy (這裡的 xy 是恰好兩個八進制位, 並且不是一個 後引用)八進制值為 0xy 的字元
\xyz (這裡的 xyz 是恰好三位八進制位, 並且不是一個 後引用) 八進制值為 0xy的字元

十六進制位是 0-9a-f,和 A-F。八進制位是 0-7

字元項逃逸總是被當作普通字元。比如,\135 是 ASCII 中的 ], 但 \135 並不終止一個方括弧資料表達式。

Table 9-16. 正則資料表達式資料表縮寫逃逸

逃逸描述
\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\D],它原來等效於 [a-c^[:digit:]]的,也是非法的。)

Table 9-17. 正則資料表達式約束逃逸

逃逸描述
\A 只匹配字串開頭,(參閱 Section 9.7.3.5 獲取它和 ^ 區別的訊息)
\m 只匹配一個詞的開頭
\M 只匹配一個詞的結尾
\y 只匹配一個詞的開頭或者結尾
\Y 只匹配那些既不是詞的開頭也不是詞的結尾的點
\Z 只匹配一個字串的結尾 (參閱 Section 9.7.3.5 獲取它和$區別的訊息)

一個詞的定義是上面 [[:<:]][[:>:]] 的聲明。在方括弧資料表達式裡,約束逃逸是非法的。

Table 9-18. 正則資料表達式後引用

逃逸描述
\m (這裡的 m 是一個非零十進制位) 一個指向第 m 個子資料表達式的後引用
\mnn (這裡的 m 是一個非零十進制位,而 nn 是更多的十進制位,並且十進制數值 mnn 不能大於到這個位置為止的閉合捕獲圓括弧的個數) 一個指向第 mnn 個子資料表達式的後引用

注意: 在八進制字元項逃逸和後引用之間有一個歷史繼承的歧義存在,這個歧義是 透過啟發分析解決的,像上面描述地那樣。前導零總是資料表示這是一個八進制逃逸。 而單個非零數字,如果沒有跟著任何其它數字,那麼總是認為是後引用。 一個多資料位的非零開頭的序列也認為是後引用——只要它在合適的子資料表達式後面 (也就是說。數值在後引用的合法範圍那),否則就認為是一個八進制。

9.7.3.4. 正則資料表達式元語法

除了上面描述地主要語法之外,還有幾種特殊形式和雜項語法。

通常,RE 的風味由 regex_flavor 決定。但是,這個環境變量 可以被一個指示器前綴覆蓋。如果一個 RE 以***: 開頭,那麼剩下的 RE 都被當作 ARE,不管 regex_flavor 是什麼。 如果任何類型的 RE 以 ***=開頭, 那麼剩下的 RE 被當作一個文本串,所有的字元都被認為是一個普通字元。

一個 ARE 可以以嵌入選項開頭:一個(?xyz) 序列(這裡的 xyz 是一個或多個字母字元)聲明影響剩餘 RE 的選項。 這些選項覆蓋任何前面判斷的選項(包括 RE 風味和大小寫敏感性)。可用的選項字母 在 Table 9-19 顯示。

Table 9-19. ARE 嵌入選項字母

選項描述
b 剩下的 RE 是 BRE
c 大小寫敏感匹配(覆蓋操作符類型)
e 剩下的 RE 是 ERE
i 大小寫不敏感匹配(參閱 Section 9.7.3.5) (覆蓋操作符類型)
m n 的歷史同義詞
n 新行敏感匹配(參閱 Section 9.7.3.5
p 部分新行敏感匹配(參閱 Section 9.7.3.5
q 重置 RE 為一個文本("引起")字串,所有都是普通字元
s 非新行敏感匹配(預設)
t 緊語法(預設,見下文)
w 反轉部分新行敏感("怪異")匹配(參閱 Section 9.7.3.5
x 擴展的語法(見下文)

嵌入地選項在終止其序列的 ) 發生作用。他們只在 ARE 的開始處起作用 (如果有,則在任何 ***: 指示器後面)。

除了通常的()RE 語法,(這種情況下所有字元都重要), 還有一種擴展語法,可以透過聲明嵌入的 x 選項獲得。 在擴展語法裡,RE 中的空白字元被忽略,就像那些在 # 和新行之間 的字元一樣。這樣就允許我們給一個複雜的 RE 分段和註釋。不過這個基本規則 上有三種例外:

  • 前置了 \ 的空白字元或者 # 保留

  • 方括弧裡的空白或者 # 保留

  • 在多字元符號裡面不能出現空白和註釋,比如 (?:

在這裡,空白是空格,水平製資料表符,新行,和任何屬於 space (空白)字元資料表的字元。

最後,在 ARE 裡,方括弧資料表達式外面,序列 (?#ttt) (這裡的 ttt 是任意不包含 ) 的文本)是一個註釋, 完全被忽略。同樣,這樣的東西是不允許出現在多字元符號的字元中間的, 比如 (?:。這樣的註釋是比有用的機制的更久遠的歷史造成的, 他們的用法已經廢棄了;我們應該使用擴展語法代替他。

如果聲明了一個初始化的 ***= 指示器,那麼所有這些元語法 擴展都不能使用,因為這樣資料表示把用戶輸入當作一個文本字串 而不是 RE 對待。

9.7.3.5. 正則資料表達式匹配規則

在 RE 可以匹配給出的字串中多於一個子字串的情況下, RE 匹配字串中最靠前的那個子字串。如果 RE 可以匹配在那個位置開始 的多個子字串,要麼是取最長的子字串,要麼是最短的,具體哪種, 取決於 RE 是貪婪的 還是 非貪婪的

一個 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 開始的東西,並且它匹配從這個位置開始的最長的字串, 也就是,Y123。輸出是這裡的圓括弧包圍的部分,或者說是 123。 在第二個例子裡, RE 總體上是一個非貪婪的 RE,因為 Y*? 是非貪婪的。 它可以匹配從 Y 開始的最短的子字串,也就是說 Y1。 子資料表達式 [0-9]{1,3} 是貪婪的,但是它不能修改總體匹配長度的決定; 因此它被迫只匹配 1

簡單說,如果一個 RE 同時包含貪婪和非貪婪的子資料表達式, 那麼總匹配長度要麼是最長可能,要麼是最短可能,取決於給整個 RE 賦予的貪婪屬性。 給子資料表達式賦予的貪婪屬性只影響在這個匹配裡,各個子資料表達式之間相互允許"吃進"的多少。

量詞 {1,1}{1,1}? 可以分別用於在一個子資料表達式或者整個 RE 上強制貪婪或者非貪婪。

匹配長度是以字元衡量的,而不是集合的元素。一個空字串會被認為比什麼都不匹配長。 比如:bb* 匹配 abbbc 的中間三個字元; (week|wee)(night|knights) 匹配 weeknights 的所有十個字元; 而 (.*).* 匹配 abc的時候,圓括弧包圍的子資料表達式 匹配所有三個字元;而如果用 (a*)* 匹配 bc,那麼 RE 和圓括弧 子資料表達式都匹配整個字串。

如果聲明了大小寫無關的匹配,那麼效果就好像把所有字母上的 大小寫區別取消了一樣。如果一個存在大小寫差別的字母以一個 普通字元的形式出現在方括弧資料表達式外面,那麼它實際上被轉換成 一個包含大小寫的方括弧資料表達式,也就是說,x 變成 [xX]。 如果它出現在一個方括弧資料表達式裡面,那麼它的所有大小寫的同族都被加入 方括弧資料表達式中,也就是說,[x] 變成 [xX], 而 [^x] 變成 [^xX]

如果聲明了新行敏感匹配,. 和使用^的方括弧資料表達式 將永遠不會匹配新行字元(這樣,匹配就絕對不會誇新行,除非 RE 明確地安排了 這樣的情況)並且^$ 除了分別匹配 字串開頭和結尾之外,還將分別匹配新行後面和前面 的空字串。但是 ARE 逃逸 \A\Z 仍然匹配字串的開頭和結尾。

如果聲明了部分新行敏感匹配,那麼它影響 . 和方括弧資料表達式, 這個時候和新行敏感匹配一樣,但是不影響 ^$

如果聲明了反轉新行敏感匹配,那麼它影響 ^$, 作用和新行敏感匹配裡一樣,但是不影響 . 和方括弧資料表達式。 這個沒什麼太多用途,只是為了對稱提供的。

9.7.3.6. 限制和相容性

在這個實現裡,對 RE 的長度沒有特別的限制,但是,那些希望能夠 有很好移植行的程序應該避免寫超過 256 字元的 RE,因為 POSIX 兼容 的實現可以拒絕接受這樣的 RE。

ARE 實際上和 POSIX ERE 不兼容的唯一的特性是在方括弧資料表達式裡 \ 並不 失去它特殊的含義。所有其它 ARE 特性都使用在 POSIX ERE 裡面是非法或者是 未定義、未聲明效果的語法;指示器的 *** 就是再 POSIX 的 BRE 和 ERE 之外的語法。

許多 ARE 擴展都是從 Perl 那裡借來的,但是有些我做了修改,清理了 一下,以及一些Perl裡沒有出現的擴展。要注意的不兼容包括 \b\B,對結尾的新行缺乏特別的處理,對那些新行敏感匹配的附加的 補齊方括弧資料表達式,在前瞻約束裡對圓括弧和方括弧引用的限制,以及最長/最短 匹配(而不是第一匹配)語義。

PostgreSQL 7.4 之前的版本裡的 ARE 和 ERE 存在兩個非常 顯著的不兼容:

  • 在 ARE 裡,後面跟著一個字母數字的 \ 要麼是一個逃逸,要麼是錯誤, 但是在以前的版本裡,她只是寫那個字母數字的另外一種方法。這個應該不是什麼問題, 因為在以前的版本裡沒有什麼原因讓我們寫這樣的序列。

  • 在 ARE 裡,\[]裡還是一個特殊字元, 因此在方括弧資料表達式裡的一個文本 \ 必須寫成 \\

雖然這些區別對大多數應用都來說都可能不是問題, 但必要時您可以透過設置 regex_flavorextended 來避免這些問題。

9.7.3.7. 基本正則資料表達式

BRE 在幾個方面和 ERE 不太一樣。|+,和 ? 都是普通字元,它們沒有等效的功能替換。範圍的分隔符是 \{\}, 因為 {} 本身是普通字元。嵌套的子資料表達式的圓括弧是 \(\),因為 () 自身是普通字元。 除非在 RE 開頭或者是圓括弧封裝的子資料表達式開頭,^ 都是普通字元, 除非在 RE 結尾或者是圓括弧封裝的子資料表達式的結尾,$ 是一個普通字元, 而如果 * 出現在 RE 開頭或者是圓括弧封裝的子資料表達式開頭 (前面可能有 ^ ),那麼它是個普通字元。 最後,可以用單數字的後引用,以及 \<\> 分別是 [[:<:]][[:>:]]的同義詞;沒有其它的逃逸。