正規表達式

正規表達式由一個或多個字元型文字和/或元字元組成。在最簡單的格式下,正規表達式僅由字元文字組成,如正規表達式 cat。它被讀作字母 c,接著是字母 a 和 t,這種模式匹配 cat、location 和 catalog 之類的字元串。可以用它們驗證數據、識別重複關鍵字的出現、檢測不必要的空格、分析字元串、驗證電話號碼、郵政編碼、電子郵件地址、社會安全號碼、IP 地址、檔案名稱和路徑名等的格式,也可以查找如 HTML 標記、數字、日期之類的模式,或任意文本數據中符合任意模式的任何事物,並用其它的模式來替換它們。

定義及介紹

正規表達式由一個或多個字元型文字和/或元字元組成。在最簡單的格式下,正規表達式僅由字元文字組成,如正規表達式 cat。它被讀作字母 c,接著是字母 a 和 t,這種模式匹配 cat、location 和 catalog 之類的字元串。元字元提供算法來確定 Oracle 如何處理組成一個正規表達式的字元。當您了解了各種元字元的含義時,您將體會到正規表達式用於查找和替換特定的文本數據是非常強大的。

驗證數據、識別重複關鍵字的出現、檢測不必要的空格,或分析字元串只是正規表達式的許多套用中的一部分。您可以用它們來驗證電話號碼、郵政編碼、電子郵件地址、社會安全號碼、IP 地址、檔案名稱和路徑名等的格式。此外,您可以查找如 HTML 標記、數字、日期之類的模式,或任意文本數據中符合任意模式的任何事物,並用其它的模式來替換它們。

正規表達式

您可以使用最新引進的 Oracle SQL REGEXP_LIKE 操作符和 REGEXP_INSTR、REGEXP_SUBSTR 以及 REGEXP_REPLACE 函式來發揮正規表達式的作用。您將體會到這個新的功能如何對 LIKE 操作符和 INSTR、SUBSTR 和 REPLACE 函式進行了補充。實際上,它們類似於已有的操作符,但現在增加了強大的模式匹配功能。被搜尋的數據可以是簡單的字元串或是存儲在資料庫字元列中的大量文本。正規表達式讓您能夠以一種您以前從未想過的方式來搜尋、替換和驗證數據,並提供高度的靈活性。

基本例子

在使用這個新功能之前,您需要了解一些元字元的含義。句號 (.) 匹配一個正規表達式中的任意字元(除了換行符)。例如,正規表達式 a.b 匹配的字元串中首先包含字母 a,接著是其它任意單個字元(除了換行符),再接著是字母 b。字元串 axb、xaybx 和 abba 都與之匹配,因為在字元串中隱藏了這種模式。如果您想要精確地匹配以 a 開頭和以 b 結尾的一條三個字母的字元串,則您必須對正規表達式進行定位。脫字元號 (^) 元字元指示一行的開始,而美元符號 ($) 指示一行的結尾(參見表1:附表見第4頁)。因此, 正規表達式 ^a.b$ 匹配字元串 aab、abb 或 axb。將這種方式與 LIKE 操作符提供的類似的模式匹配 a_b 相比較,其中 (_) 是單字元通配符。

默認情況下,一個正規表達式中的一個單獨的字元或字元列表只匹配一次。為了指示在一個正規表達式中多次出現的一個字元,您可以使用一個量詞,它也被稱為重複操作符。.如果您想要得到從字母 a 開始並以字母 b 結束的匹配模式,則您的正規表達式看起來像這樣:^a.*b$。* 元字元重複前面的元字元 (.) 指示的匹配零次、一次或更多次。LIKE 操作符的等價的模式是 a%b,其中用百分號 (%) 來指示任意字元出現零次、一次或多次。

表 2 給出了重複操作符的完整列表。注意它包含了特殊的重複選項,它們實現了比現有的 LIKE 通配符更大的靈活性。如果您用圓括弧括住一個表達式,這將有效地創建一個可以重複一定次數的子表達式。例如,正規表達式 b(an)*a 匹配 ba、bana、banana、yourbananasplit 等。

Oracle 的正規表達式實施支持 POSIX (可移植作業系統接口)字元類,參見表 3 中列出的內容。這意味著您要查找的字元類型可以非常特別。假設您要編寫一條僅查找非字母字元的 LIKE 條件 — 作為結果的 WHERE 子句可能不經意就會變得非常複雜。

POSIX 字元類必須包含在一個由方括弧 ([]) 指示的字元列表中。例如,正規表達式 [[:lower:]] 匹配一個小寫字母字元,而 [[:lower:]] 匹配五個連續的小寫字母字元。

除 POSIX 字元類之外,您可以將單獨的字元放在一個字元列表中。例如,正規表達式 ^ab[cd]ef$ 匹配字元串 abcef 和 abdef。必須選擇 c 或 d。

除脫字元 (^) 和連字元 (-) 之外,字元列表中的大多數元字元被認為是文字。正規表達式看起來很複雜,這是因為一些元字元具有隨上下文環境而定的多重含義。^ 就是這樣一種元字元。如果您用它作為一個字元列表的第一個字元,它代表一個字元列表的非。因此,[^[:digit:]] 查找包含了任意非數字字元的模式,而 ^[[:digit:]] 查找以數字開始的匹配模式。連字元 (-) 指示一個範圍,正規表達式 [a-m] 匹配字母 a 到字母 m 之間的任意字母。但如果它是一個字元行中的第一個字元(如在 [-afg] 中),則它就代表連字元。

之前的一個例子介紹了使用圓括弧來創建一個子表達式;它們允許您通過輸入更替元字元來輸入可更替的選項,這些元字元由豎線 (|) 分開。

例如,正規表達式 t(a|e|i)n 允許字母 t 和 n 之間的三種可能的字元更替。匹配模式包括如 tan、ten、tin 和 Pakistan 之類的字,但不包括 teen、mountain 或 tune。作為另一種選擇,正規表達式 t(a|e|i)n 也可以表示為一個字元列表 t[aei]n。表 4 匯總了這些元字元。雖然存在更多的元字元,但這個簡明的概述足夠用來理解這篇文章使用的正規表達式。

後向引用

正規表達式的一個有用的特性是能夠存儲子表達式供以後重用;這也被稱為後向引用(在表 10 中對其進行了概述)。它允許複雜的替換功能,如在新的位置上交換模式或顯示重複出現的單詞或字母。子表達式的匹配部分保存在臨時緩衝區中。緩衝區從左至右進行編號,並利用 \digit 符號進行訪問,其中 digit 是 1 到 9 之間的一個數字,它匹配第 digit 個子表達式,子表達式用一組圓括弧來顯示。

接下來的例子顯示了通過按編號引用各個子表達式將姓名 Ellen Hildi Smith 轉變為 Smith, Ellen Hildi。

SELECT REGEXP_REPLACE(

'Ellen Hildi Smith',

'(.*) (.*) (.*)', '\3, \1 \2')

FROM dual

REGEXP_REPLACE('EL

------------------

Smith, Ellen Hildi

該 SQL 語句顯示了用圓括弧括住的三個單獨的子表達式。每一個單獨的子表達式包含一個匹配元字元 (.),並緊跟著 * 元字元,表示任何字元(除換行符之外)都必須匹配零次或更多次。空格將各個子表達式分開,空格也必須匹配。圓括弧創建獲取值的子表達式,並且可以用 \digit 來引用。第一個子表達式被賦值為 \1 ,第二個 \2,以此類推。這些後向引用被用在這個函式的最後一個參數 (\3, \1 \2) 中,這個函式有效地返回了替換子字元串,並按期望的格式來排列它們(包括逗號和空格)。表 11 詳細說明了該正規表達式的各個組成部分。

後向引用對替換、格式化和代替值非常有用,並且您可以用它們來查找相鄰出現的值。接下來的例子顯示了使用 REGEP_SUBSTR 函式來查找任意被空格隔開的重複出現的字母數字值。顯示的結果給出了識別重複出現的單詞 is 的子字元串。

SELECT REGEXP_SUBSTR(

'The final test is is the implementation',

'([[:alnum:]]+)([[:space:]]+)\1') AS substr

FROM dual

SUBSTR

------

is is

匹配參數選項

您可能已經注意到了正規表達式操作符和函式包含一個可選的匹配參數。這個參數控制是否區分大小寫、換行符的匹配和保留多行輸入。

實際套用

您不僅可以在佇列中使用正規表達式,還可以在使用 SQL 操作符或函式的任何地方(比如說在 PL/SQL 語言中)使用正規表達式。您可以編寫利用正規表達式功能的觸發器,以驗證、生成或提取值。

接下來的例子演示了您如何能夠在一次列檢查約束條件中套用 REGEXP_LIKE 操作符來進行數據驗證。它在插入或更新時檢驗正確的社會保險號碼格式。如 123-45-6789 和 123456789 之類格式的社會保險號碼對於這種列約束條件是可接受的值。有效的數據必須以三個數字開始,緊跟著一個連字元,再加兩個數字和一個連字元,最後又是四個數字。另一種表達式只允許 9 個連續的數字。豎線符號 (|) 將各個選項分開。

ALTER TABLE students

ADD CONSTRAINT stud_ssn_ck CHECK

(REGEXP_LIKE(ssn,

'^([[:digit:]]-[[:digit:]]-[[:digit:]]|[[:digit:]])$'))

由 ^ 和 $ 指示的開頭或結尾的字元都是不可接受的。確保您的正規表達式沒有分成多行或包含任何不必要的空格,除非您希望格式如此並相應地進行匹配。表 12 說明了該正規表達式示例的各個組成部分。

功能比較

正規表達式有幾個優點優於常見的 LIKE 操作符和 INSTR、SUBSTR 及 REPLACE 函式的。這些傳統的 SQL 函式不便於進行模式匹配。只有 LIKE 操作符通過使用 % 和 _ 字元匹配,但 LIKE 不支持表達式的重複、複雜的更替、字元範圍、字元列表和 POSIX 字元類等等。此外,新的正規表達式函式允許檢測重複出現的單詞和模式交換。這裡的例子為您提供了正規表達式領域的一個概覽,以及您如何能夠在您的應用程式中使用它們。

豐富工具包

因為正規表達式有助於解決複雜的問題,所以它們是非常強大的。正規表達式的一些功能難於用傳統的 SQL 函式來仿效。當您了解了這種稍顯神秘的語言的基礎構建程式塊時,正規表達式將成為您的工具包的不可缺少的一部分(不僅在 SQL 環境下也在其它的程式語言環境下)。為了使您的各個模式正確,雖然嘗試和錯誤有時是必須的,但正規表達式的簡潔和強大是不容置疑的。

正規表達式詳細定義

正規表達式(regular expression)描述了一種字元串匹配的模式,可以用來檢查一個串是否含有某種子串、將匹配的子串做替換或者從某個串中取出符合某個條件的子串等。

列目錄時, dir *.txt或ls *.txt中的*.txt就不是一個正規表達式,因為這裡*與正規式的*的含義是不同的。

正規表達式是由普通字元(例如字元 a 到 z)以及特殊字元(稱為元字元)組成的文字模式。正規表達式作為一個模板,將某個字元模式與所搜尋的字元串進行匹配。

1. 普通字元

由所有那些未顯式指定為元字元的列印和非列印字元組成。這包括所有的大寫和小寫字母字元,所有數字,所有標點符號以及一些符號。

2. 非列印字元 字元 含義

\cx 匹配由x指明的控制字元。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字元。

\f 匹配一個換頁符。等價於 \x0c 和 \cL。

\n 匹配一個換行符。等價於 \x0a 和 \cJ。

\r 匹配一個回車符。等價於 \x0d 和 \cM。

\s 匹配任何空白字元,包括空格、制表符、換頁符等等。等價於 [ \f\n\r\t\v]。

\S 匹配任何非空白字元。等價於 [^ \f\n\r\t\v]。

\t 匹配一個制表符。等價於 \x09 和 \cI。

\v 匹配一個垂直制表符。等價於 \x0b 和 \cK。

3.  特殊字元

所謂特殊字元,就是一些有特殊含義的字元,如上面說的"*.txt"中的*,簡單的說就是表示任何字元串的意思。如果要查找檔案名稱中有*的檔案,則需要對*進行轉義,即在其前加一個\。ls \*.txt。正規表達式有以下特殊字元。

特別字元 說明

$ 匹配輸入字元串的結尾位置。如果設定了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字元本身,請使用 \$。

( ) 標記一個子表達式的開始和結束位置。子表達式可以獲取供以後使用。要匹配這些字元,請使用 \( 和 \)。

* 匹配前面的子表達式零次或多次。要匹配 * 字元,請使用 \*。

+ 匹配前面的子表達式一次或多次。要匹配 + 字元,請使用 \+。

. 匹配除換行符 \n之外的任何單字元。要匹配 .,請使用 \。

[ 標記一個中括弧表達式的開始。要匹配 [,請使用 \[。

? 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字元,請使用 \?。

\ 將下一個字元標記為或特殊字元、或原義字元、或向後引用、或八進制轉義符。例如, 'n' 匹配字元 'n'。'\n' 匹配換行符。序列 '\\' 匹配 "\",而 '\(' 則匹配 "("。

^ 匹配輸入字元串的開始位置,除非在方括弧表達式中使用,此時它表示不接受該字元集合。要匹配 ^ 字元本身,請使用 \^。

{ 標記限定符表達式的開始。要匹配 {,請使用 \{。

| 指明兩項之間的一個選擇。要匹配 |,請使用 \|。

構造正規表達式的方法和創建數學表達式的方法一樣。也就是用多種元字元與操作符將小的表達式結合在一起來創建更大的表達式。正規表達式的組件可以是單個的字元、字元集合、字元範圍、字元間的選擇或者所有這些組件的任意組合。

4.  限定符

限定符用來指定正規表達式的一個給定組件必須要出現多少次才能滿足匹配。有*或+或?或或{n,}或{n,m}共6種。

*、+和?限定符都是貪婪的,因為它們會儘可能多的匹配文字,只有在它們的後面加上一個?就可以實現非貪婪或最小匹配。

正規表達式的限定符有:

字元 描述

* 匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價於{0,}。

+ 匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。

? 匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價於 {0,1}。

n 是一個非負整數。匹配確定的 n 次。例如,'o' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。

{n,} n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。

{n,m} m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。

5.  定位符

用來描述字元串或單詞的邊界,^和$分別指字元串的開始與結束,\b描述單詞的前或後邊界,\B表示非單詞邊界。不能對定位符使用限定符。

6.  選擇

用圓括弧將所有選擇項括起來,相鄰的選擇項之間用|分隔。但用圓括弧會有一個副作用,是相關的匹配會被快取,此時可用?:放在第一個選項前來消除這種副作用。

其中?:是非捕獲元之一,還有兩個非捕獲元是?=和?!,這兩個還有更多的含義,前者為正向預查,在任何開始匹配圓括弧內的正規表達式模式的位置來匹配搜尋字元串,後者為負向預查,在任何開始不匹配該正規表達式模式的位置來匹配搜尋字元串。

7.  後向引用

對一個正規表達式模式或部分模式兩邊添加圓括弧將導致相關匹配存儲到一個臨時緩衝區中,所捕獲的每個子匹配都按照在正規表達式模式中從左至右所遇到的內容存儲。存儲子匹配的緩衝區編號從 1 開始,連續編號直至最大 99 個子表達式。每個緩衝區都可以使用 '\n' 訪問,其中 n 為一個標識特定緩衝區的一位或兩位十進制數。

可以使用非捕獲元字元 '?:', '?=", or "?!' 來忽略對相關匹配的保存。

相關詞條

相關搜尋

熱門詞條

聯絡我們