正則表達式
正則表達式用於查找和替換字符串中的模式。正則表達式是用某種語法定義的,正則表達式引擎采用這種語法並將它與字符串進行比較。引擎返回字符串是否與語法匹配的指示;也即,該字符串是否包含能夠從該語法派生的子串。此外,引擎還能夠返回匹配的子串。術語“模式(pattern)”用來表示語法。
最基本的模式僅由單個字母組成。當與該模式進行比較時,包含這個字母的字符串就是一個“匹配”。例如,如果模式是“a”,則字符串“abcd”就是一個匹配,而字符串“xyz”則不是。正則表達式的強大功能來自於預定義的運算符(也稱為元字符),它們可以用很小的空間來表示模式。根據“方言”和受支持的功能,可以使用不同的元字符。通常,其中的一些可用字符如下:
| — 二中擇一[ ] — 分組* — 多次出現(也匹配零次出現)+ — 多次出現(至少一次)? — 隨意的出現次數\\\\ — 反斜槓
不同的系統實現了常用正則表達式的各種擴展。編程語言 Perl 中使用的正則表達式支持進一步的縮寫。本文中所用的庫實現了這些擴展。下面摘錄了其中部分可以在 Perl 正則表達式語言中使用的縮寫:
\\s — 任意空白字符\\w — 任意字母數字字符\\d — 任意數字字符
另一個更高級的示例是模式“[A-Z]* = ([0-9]|0x00);”。與這個模式相匹配的字符串包含這樣的子串:它由幾個大寫字母、後面跟上一個空格、一個等號、另一個空格,然後是一個數字或字符串“0x00”組成。該子串的最後一個字符必須是分號。使用 Perl,這個模式可以表示為“\\w* = (\\d|0x00);”。“NM = 0x00;”和“X = 7;”是兩個可以與該模式匹配的字符串。但字符串“Z = 123;”不能匹配,因為 123 是由三個數字所組成的。
DB2 中的字符串匹配
除了 Extender 以外,DB2 還允許幾種用於文本比較的函數和運算符。但那些函數和運算符要麼在用於模式匹配的功能方面有限制,要麼就是會給可能使用它們的查詢帶來復雜性。這裡簡要地摘錄幾個可用的功能:
= 或 <> 謂詞:逐字符地比較兩個字符串是否相等。
LIKE 謂詞:使用通配符的基本模式匹配。
LOCATE 函數:在字符串中查找子串。
盡管也可以用 SQL 運算符表示模式“[A-Z]* = ([0-9]|0x00);”,但那樣會很麻煩。例如,下列 SELECT 語句的 WHERE 子句中所使用的謂詞會匹配字符串“str”中等號之後的部分,如 清單 1所示:
清單 1. 使用 LIKE 匹配模式
SELECT strFROM strTableWHERE ( str LIKE '% = 0;%' OR str LIKE '% = 1;%' OR str LIKE '% = 2;%' OR str LIKE '% = 3;%' OR str LIKE '% = 4;%' OR str LIKE '% = 5;%' OR str LIKE '% = 7;%' OR str LIKE '% = 7;%' OR str LIKE '% = 8;%' OR str LIKE '% = 9;%' OR str LIKE '% = 0x00;%' )
這增加了可以匹配“[A-Z]*”子模式的謂詞的復雜度,這可以使用對整個字符串進行迭代並進行逐字符比較的函數來完成,但您會發現使用內置功能既冗長又復雜。
示例方案
讓我們定義下列清單( 清單 2)並插入幾行:
清單 2. 創建我們的樣本表
CREATE TABLE strTable ( c1 INTEGER, str VARCHAR(500) );INSERT INTO strTable VALUES ( 1, 'some text;' ), ( 2, 'variable = 1234;' ), ( 3, 'var2 = ''string variable'';' ), ( 4, 'xyz = ' ), ( 5, 'myVar = 0x00;' ), ( 6, '# comment' ), ( 7, 'abc = def' );
這個 清單及其數據被用於下面的所有示例。
SELECT * FROM strTable;C1 STR----------- ------------------------------ 1 some text; 2 variable = 1234; 3 var2 = 'string variable'; 4 xyz = 5 myVar = 0x00; 6 # comment 7 abc = def 7 record(s) selected.
實現模式匹配函數
您可以使用 DB2 的可擴展機制,在 SQL 語句內使用 UDF,以便顯著地改善這種情形。通過定義名為 regex1 的 UDF(它采用模式和字符串作為輸入參數), 清單 1中的 WHERE 子句現在可以寫得象 清單 3中所示的那樣:
清單 3. 使用 regex UDF 來簡化模式匹配
SELECT strFROM strTableWHERE regex1('\\w* = (\\d|0x00);', str) = 1
在本示例中,使用帶有 Perl 擴展的正則表達式來匹配完整的模式,而不僅僅是 清單 1中給出的 LIKE 謂詞所對應的部分模式。正如您所看到的,使用函數來為該模式編寫謂詞比用 LIKE 謂詞表示同樣的語義要容易得多。
實現 UDF
在我的示例實現中,我選擇了現有的名為 PCRE(Perl 兼容的正則表達式,Perl-compatible regular expression)的模式匹配引擎。該引擎提供了用來處理模式和執行匹配的 C API。該引擎和查詢中所用的 SQL 語言之間“缺失的部分”是 UDF。該 UDF 由兩部分組成:
清單 4顯示了用於創建該函數的 SQL 語句。
清單 4. 注冊 regex1 函數
CREATE FUNCTION regex1(pattern VARCHAR(2048), string CLOB(10M)) RETURNS INTEGER SPECIFIC regexSimple EXTERNAL NAME 'regexUdf!regexpSimple' LANGUAGE C PARAMETER STYLE DB2SQL DETERMINISTIC NOT FENCED RETURNS NULL ON NULL INPUT NO SQL NO EXTERNAL ACTION ALLOW PARALLEL;
注:請參閱 DB2 SQL Reference以獲取所有子句的詳細含義。可以修改參數的長度以適應您的需求。我在此處展示某些值並沒有任何推薦使用它們的用意。