一.簡介
正則表達式的作用是匹配文本,將一個模式(正則表達式)與一個文本串進行比較。MySQL用where子句對正則表達式提供支持,允許指定正則表達式過濾select檢索出的數據。
二.基本字符匹配
輸入
select name from product where name regexp '1';
輸出
分析
除關鍵字like被regexp替代外,這條語句看上去像like語句。它告訴MYSQL:REGEXP后所跟的東西作為正則表達式處理。
為什么要費力地使用正則表達式?在剛才的例子中,正則表達式確實沒有帶來太多好處(可能還會降低性能),不過,請考慮下面的例子:
輸入
select name from product where name regexp '.22';
輸出
分析
這里使用了正則表達式 .22。.是正則表達式語言中一個特殊的字符。它表示匹配任意一個字符,因此,322和122都匹配且返回。
Like與REGEXP 在LIKE和REGEXP之間有一個重要的差別。
請看以下兩條語句:
select name
from product
where name like '322';
select name
from product
where name regexp '322';
如果執行上述兩條語句,會發現第一條語句不返回數據,而第二條語句返回一行。為什么?
這是因為like匹配整個列。如果被匹配的文本在列值中出現,like將不會找到它,相應的行也不被返回(除非使用通配符)。而regexp在列值內進行匹配,如果被匹配的文本在列值中出現,regexp將會找到它,相應的行將被返回。這是一個非常重要的差別。
那么,regexp能不能用來匹配整個列值(從而起與like相同的作用)?答案是肯定的,使用^和$定位符即可。
匹配不區分大小寫 MySQL中的正則表達式匹配(自版本3.23.4后)不區分大小寫(即,大小寫都匹配)。為區分大小寫,可使用BINARY關鍵字,如where name regexp binary 'Product.22'.
三.進行OR匹配
為搜索兩個串之一(或者為這個串,或者為另一個串),使用|,如下所示:
輸入
select name from product where name regexp '122|322';
輸出
分析
語句中使用了正則表達式122|322。|為正則表達式的OR操作符。它表示匹配其中之一,因此122和322都匹配并返回。
使用|從功能上類似于select語句中使用OR語句,多個OR條件可并入單個正則表達式。
兩個以上的OR條件 可以給出兩個以上的OR條件。例如,‘122|322|422’將匹配122或322或422
四.匹配幾個字符之一
匹配任何單一字符。但是,如果你只想匹配特定的字符,怎么辦?可通過指定一組【和】括起來的字符來完成,如下所示:
輸入
select name from product where name regexp '[123] pro';
輸出
分析
這里,使用了正則表達式[123] pro。[123]定義一組字符,它的意思是匹配1或2或3,因此,1 pro和2 pro都匹配且返回(沒有3 pro)。
正如所見,[]是另一種形式的OR語句。事實上,正則表達式[123] pro為[1|2|3] pro的縮寫,也可以使用后者。但是,需要是[]來定義OR語句查找什么。為更好理解這一點,可以查看下面的例子:
輸入
select name from product where name regexp '1|2|3 pro';
輸出
分析
這并不是期望的輸出。兩個要求的行被檢索出來,但還檢索出了另外3行。之所以這樣是由于MySQL假定你的意思是'1'或'2'或'3 pro'。除非把字符|括在一個集合中,否則它將應用于整個串。
字符集合也可以被否定,即,它們將匹配除指定字符外的任何東西。為否定一個字符集,在集合的開始處放置一個即可。因此,盡管[123]匹配字符1、2或3,但[123]卻匹配除這些字符外的任何東西。
五.匹配范圍
集合可用來定義要匹配的一個或多個字符。例如,下面的集合將匹配數字0到9:
[0123456789]
為簡化這種類型的集合,可使用-來定義一個范圍。下面的式子功能上等同于上述數字列表:
[0-9]
范圍不限于完整的集合,[1-3]和[6-9]也是合法的范圍。此外,范圍不一定只是數值的,[a-z]匹配任意字母字符。
例子如下
輸入
select name from product where name regexp '[1-4] pro';
輸出
分析
這里使用正則表達式[1-4] pro。[1-4]定義了一個范圍,這個表達式意思是匹配1到4.因此返回3個匹配行。由于3 pro匹配,所以返回y3 pro apple。
六.匹配特殊字符
正則表達式語言由具有特定含義的特殊字符構成。我們已經看到“.”、“[]”、“|”和“-”等,還有其他一些字符。請問,如果你需要匹配這些字符,應該怎么辦呢?例如,如果要找出包含“.”字符的值,怎么搜索?請看下面的例子:
輸入
select name from product where name regexp '.';
輸出
分析
這并不是期望的輸出,.匹配任意字符,因此每個行都被檢索出來
為了匹配特殊字符,必須使用\\為前導。\\-表示查找-,\\.表示查找.。
輸入
select name from product where name regexp '\\.';
輸出
分析
這才是期望的輸出。\\.匹配.,所以只檢索出一行。這種處理就是所謂的轉義,正則表達式內具有特殊意義的所有字符都必須以這種方式轉義。這包括“.”、“|”、“[]”以及至今為止使用過的其他特殊字符。
\\也用來引用元符號(具有特殊含義的字符),如下面所列。
元字符 | 說明 |
---|---|
\\f | 換頁 |
\\n | 換行 |
\\r | 回車 |
\\t | 制表 |
\\v | 縱向制表 |
匹配\ 為了匹配反斜杠(\)字符本身,需要使用\\\
\或\\? 多數正則表達式實現使用單個反斜杠轉義特殊字符,以便能使用這些字符本身。但MySQL要求兩個反斜杠(MySQL自己解釋一個,正則表達式解釋另一個)
七.匹配字符類
存在找出你自己經常使用的數字、所有字母字符或所有數字字母字符等的匹配。為更方便工作,可以使用預定義的字符集,稱為字符類。下面列出字符類以及它們的含義。
元字符 | 說明 |
---|---|
[:alnum:] | 任意字母和數字(同[a-zA-Z0-9]) |
[:alpha:] | 任意字符(同[a-zA-Z]) |
[:blank:] | 空格和制表(同[\\t]) |
[:cntrl:] | ASCII控制字符(ASCII 0到31和127) |
[:digit:] | 任意數字(同[0-9]) |
[:graph:] | 與[:print:]相同,但不包括空格 |
[:lower:] | 任意小寫字母(同[a-z]) |
[:print:] | 任意可打印字符 |
[:punct:] | 既不在[:alnum:]又不在[:cntrl:]中的任意字符 |
[:space:] | 包括空格在內的任意空白字符(同[\\f\\n\\r\\t\\v]) |
[:upper:] | 任意大寫字母(同[A-Z]) |
[:xdigit:] | 任意十六進制數字(同[a-fA-F0-9]) |
八.匹配多個實例
目前為止使用的所有正則表達式都試圖匹配單次出現。如果存在一個匹配,該行被檢索出來,如果不存在,檢索不出任何行。但有時需要對匹配的數目進行更強的控制。例如,你可能需要尋找所有的數,不管數中包含多少數字,或者你可能想尋找一個單詞并且還能適應一個尾隨的s(如果存在),等等。
這可以使用下面的正則表達式重復元字符來完成。
元字符 | 說明 |
---|---|
* | 0個或多個匹配 |
+ | 1個或多個匹配(等于{1,}) |
? | 0個或1個匹配(等于{0,1}) |
{n} | 指定數目的匹配 |
{n,} | 不少于指定數目的匹配 |
{n,m} | 匹配數目的范圍(m不超過255) |
下面舉幾個例子。
輸入
select name from product where name regexp '\\([0-9] sticks?\\)';
輸出
分析
正則表達式\\([0-9] sticks?\\)需要解說一下。\\(匹配),[0-9]匹配任意數字(這個例子中為1和5),sticks?匹配stick和sticks(s后的?使s可選,因為?匹配它前面的任何字符的0次或1次出現),\\)匹配)。沒有?,匹配stick和sticks會非常困難。
以下是另一個例子。匹配連在一起的3位數字:
輸入
select name from product where name regexp '[[:digit:]]{3}';
輸出
分析
如前所述,[:digit:]匹配任意數字,因而它為數字的一個集合。{3}確切地要求它前面的字符(任意數字)出現3次,所以[[:digit:]]{3}匹配連在一起的任意三位數字。
上面的式子也可以改成下面這種形式
select name from product where name regexp '[0-9][0-9][0-9]';
九.定位符
上述的所有例子都是匹配一個串中任意位置的文本。為了匹配特定位置的文本,需要下面的定位符。
元字符 | 說明 |
---|---|
^ | 文本的開始 |
$ | 文本的結尾 |
[[:<:]] | 詞的開始 |
[[:>:]] | 詞的結尾 |
例如,如果你想找出以一個數(包括以小數點開始的數)開始的所有產品,怎么辦?簡單搜索[0-9\\.] (或[[:digit:]\\.])不行,因為它將在文本內任意位置查找匹配。解決辦法就是使用^定位符,如下所示:
輸入
select name from product where name regexp '^[0-9\\.]';
輸出
分析
匹配串的開始。因此,[0-9\\.]只在.或任意數字為串中第一個字符時才匹配它們。沒有^,則還要多檢索出4個別的行(那些中間有數字的行)。
^的雙重用途 ^有兩種用法。
在集合中(用[和]都定義),用它來否定該集合,否則,用來指串的開始處。