postgres中正規表示式及轉義

itpub120發表於2018-08-22

PostgreSQL 提供了三種實現模式匹配的方法:傳統 SQL 的  LIKE  運算子、SQL99 新增的  SIMILAR TO  運算子、 POSIX 風格的正規表示式。另外還有一個模式匹配函式  substring  可用,它可以使用  SIMILAR TO  風格或者 POSIX 風格的正規表示式。

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

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 LIKE  和  NOT ILIKE  。所有這些運算子都是 PostgreSQL 特有的。

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 正規表示式借用的模式匹配元字元:

  • |  表示選擇(兩個候選之一)

  • *  表示重複前面的項零次或更多次

  • +  表示重複前面的項一次或更多次

  • ()  把項組合成一個邏輯項

  • [...]  宣告一個字元類

請注意沒有提供範圍重複( ?  和  {...} ),儘管它們在 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

帶三個引數的  substring( string  from  pattern  for  escape-character )  函式提供了一個從字串中抽取一個匹配 SQL 正規表示式模式的子字串功能。和  SIMILAR TO  一樣,宣告的模式必須匹配整個字串,否則函式失效並返回 NULL 。為了標識在成功的時候應該返回的模式部分,模式必須出現後跟雙引號( " )的兩個逃逸字元。匹配這兩個標記之間的模式的字串將被返回。

一些例子:

substring('foobar' from '%#"o_b#"%' for '#')   oobsubstring('foobar' from '#"o_b#"%' for '#')    NULL

列出了所有用於 POSIX 正規表示式的運算子。

表9-11. 正規表示式匹配運算子

運算子 描述 例子
~ 匹配正規表示式,大小寫相關 '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

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

一些例子:

substring('foobar' from 'o.b')     oobsubstring('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  表示替換每一個匹配的子字串而不僅僅是第一個。

一些例子:

regexp_replace('foobarbaz', 'b..', 'X')                                   fooXbazregexp_replace('foobarbaz', 'b..', 'X', 'g')                                   fooXXregexp_replace('foobarbaz', 'b(..)', E'X\\1Y', 'g')                                   fooXarYXazY

PostgreSQL 的正規表示式使用 Henry Spencer 寫的一個包來實現。下面的大部分描述都是從他的手冊頁裡逐字複製過來的。

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

【注意】 我們可以透過設定執行時引數   來選擇 PostgreSQL 接受的正規表示式的形式。通常的設定是  advanced  ,但是我們可以選擇  extended  以和7.4之前的 PostgreSQL 版本做到最大程度的向下相容。

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

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

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

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

表9-12. 正規表示式原子

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

RE不能以  \  結尾。

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

表9-13. 正規表示式量詞

量詞 匹配
* 一個匹配 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-14. 正規表示式約束

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

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

方括弧表示式 是一個包圍在  []  裡的字元列表。它通常匹配任意單個列表中的字元(又見下文)。如果列表以  ^  開頭,它匹配任意單個(又見下文) 在該列表中的字元。如果該列表中兩個字元用  -  隔開,那它就是那兩個字元(包括在內)之間的所有字元範圍的縮寫,比如,在 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 ,但那裡面並沒有說明,而且在準備移植到其它系統裡去的軟體裡一定要小心使用。通常下面描述的約束逃逸更好些(他們並非更標準,但是肯定更容易輸入)。

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

字元項逃逸 用於方便我們宣告正規表示式裡那些不可列印的字元。它們在 裡列出。

類縮寫逃逸 用來提供一些常用的字元類縮寫。他們在 裡列出。

約束逃逸 是一個約束,如果滿足特定的條件,它匹配該空字串。它們在 裡列出。

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

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

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

表9-15. 正規表示式字元項逃逸

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

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

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

表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:]]  的,也是非法的。

表9-17. 正規表示式約束逃逸

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

一個詞的定義是上面  [[:<:]]  和  [[:>:]]  的宣告。在方括弧表示式裡,約束逃逸是非法的。

表9-18. 正規表示式後引用

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

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

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

通常,正規表示式的風格由  regex_flavor  決定。但是,這個環境變數可以被一個 指示器 字首覆蓋。如果一個正規表示式以  ***:  開頭,那麼不管  regex_flavor  是什麼剩下的正規表示式都被當作 ARE 。如果任何型別的正規表示式以  ***=  開頭,那麼剩下的正規表示式被當作一個文字串,所有的字元都被認為是一個普通字元。

一個 ARE 可以以 嵌入選項 開頭:一個  (? xyz )  序列(這裡的  xyz  是一個或多個字母字元)宣告影響剩餘正規表示式的選項。這些選項覆蓋任何前面判斷的選項(包括正規表示式風格和大小寫敏感性)。可用的選項字母在 顯示。

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

選項 描述
b 剩餘的正規表示式是 BRE
c 大小寫敏感匹配(覆蓋運算子型別)
e 剩餘的正規表示式是 ERE
i 大小寫不敏感匹配(參閱 )(覆蓋運算子型別)
m n  的歷史同義詞
n 新行敏感匹配(參閱 )
p 部分新行敏感匹配(參閱 )
q 重置正規表示式為一個文字("引起")字串,所有都是普通字元。
s 非新行敏感匹配(預設)
t 緊語法(預設,見下文)
w 反轉部分新行敏感("怪異")匹配(參閱 )
x 擴充套件的語法(見下文)

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

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

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

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

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

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

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

如果宣告瞭一個初始化的  ***=  指示器,那麼所有這些元語法擴充套件都 不能 使用,因為這樣表示把使用者輸入當作一個文字字串而不是正規表示式對待。

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

一個正規表示式是否貪婪取決於下面規則:

  • 大多數原子,以及所有約束,都沒有貪婪屬性(因為它們畢竟無法匹配個數變化的文字)。

  • 在一個正規表示式周圍加上圓括弧並不會改變其貪婪性。

  • 一個帶一個固定重複次數的量詞( { m }  或  { m }? )量化的原子和原子自身有著同樣的貪婪性(可能是沒有)。

  • 一個帶其它普通的量詞(包括  { m , n }  中  m  等於  n  的情況)量化的原子是貪婪的(首選最長匹配)。

  • 一個帶非貪婪量詞(包括  { m , n }?  中  m  等於  n  的情況)量化原子是非貪婪的(首選最短匹配)。

  • 一個分支(也就是一個沒有頂級  |  操作的正規表示式)和它裡面的第一個有貪婪屬性的量化原子有著同樣的貪婪性。

  • 一個由  |  運算子連線起來的兩個或者更多分支組成的正規表示式總是貪婪的。

上面的規則所描述的貪婪屬性不僅僅適用於獨立的量化原子,而且也適用於包含量化原子的分支和整個正規表示式。這裡的意思是,匹配是按照分支或者整個正規表示式 作為一個整體 匹配最長或者最短的子字串的可能。一旦整個匹配的長度確定,那麼匹配任意子表示式的部分就基於該子表示式的貪婪屬性進行判斷,在正規表示式裡面靠前的子表示式的優先順序高於靠後的子表示式。

一個表達這些的例子:

SELECT SUBSTRING('XY1234Z', 'Y*([0-9]{1,3})');Result: 123SELECT 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 存在兩個非常顯著的不相容:

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

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

雖然這些區別對大多數應用都來說都可能不是問題,但必要時你可以透過將  regex_flavor  設定為  extended  來避免這些問題。

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




來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8109090/viewspace-2212536/,如需轉載,請註明出處,否則將追究法律責任。

相關文章