MySQL用正則表達(dá)式進(jìn)行搜索

用正則表達(dá)式進(jìn)行搜索

1.正則表達(dá)式介紹

? 對(duì)于基于的過濾(或者甚至是某些不那么基本的過濾),可以用匹配、比較和通配操作符尋找數(shù)據(jù),這樣足夠了。但隨著復(fù)雜性的增加。WHERE子句的復(fù)雜性也有必要增加。

? 這也就是正則表達(dá)式變得有用的地方。正則表達(dá)式是用來匹配文本的特殊的串(字符集合)。如果你想從一個(gè)文本文件中提取電話號(hào)碼,可以使用正則表達(dá)式如果你需要查找名字中間有數(shù)字的所有文件,可以使用一個(gè)正則表達(dá)式。如果你想在一個(gè)文本塊中找到所有重復(fù)的單詞,可以使用一個(gè)正則表達(dá)式。如果你想替換一個(gè)頁面中的所有URL為這些URL的實(shí)際HTML鏈接,也可以使用一個(gè)正則表達(dá)式(對(duì)于最后這個(gè)例子,或者是兩個(gè)正則表達(dá)式)。

? 正則表達(dá)式用正則表達(dá)式語言來建立,正則表達(dá)式語言是用來完成剛討論的所有工作以及更多工作的一種特殊語言。與任意語言一樣,正則表達(dá)式具有你必須學(xué)習(xí)的特殊的語法和指令。

2.使用MySQL正則表達(dá)式

? 那么,正則表達(dá)式與MySQL有啥關(guān)系?以及說過,正則表達(dá)式的作用是匹配文本,將一個(gè)模式(正則表達(dá)式)與一個(gè)文本串進(jìn)行比較。MySQL用WHERE子句對(duì)正則表達(dá)式提供了初步的支持,允許你指定正則表達(dá)式,過濾SELECT檢索出的數(shù)據(jù)。

2.1 基本字符匹配

? 下面的語句檢索列prod_name包含文本1000的所有行:

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '1000'
ORDER BY prod_name;

輸出:

prod_name
JetPack 1000

分析:

除關(guān)鍵字LIKEREGEXP替代外,這條語句看上去非常像使用LIKE的語句。它告訴MySQL:REGEXP后所跟的東西作為正則表達(dá)式(與文字正文1000匹配的一個(gè)正則表達(dá)式)處理。

? 為什么要費(fèi)力地使用正則表達(dá)式?在剛才的例子中,正則表達(dá)式確實(shí)沒有帶來太多好處(可能還會(huì)降低性能),不過,請(qǐng)考慮下面的例子:

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '.000'
ORDER BY prod_name;

分析:這里使用了正則表達(dá)式.000。.是正則表達(dá)式語言中一個(gè)特殊的字符。它表示匹配任意一個(gè)字符,因此,1000和2000都匹配且返回。

LIKE與REGEXP

LIKEREGEXP之間有一個(gè)重要的差別。請(qǐng)看以下兩條語句:

SELECT prod_name
FROM products
WHERE prod_name LIKE '1000'
ORDER BY prod_name;

SELECT prod_name
FROM products
WHERE prod_name REGEXP '1000'
ORDER BY prod_name;

如果執(zhí)行上述兩條語句,會(huì)發(fā)現(xiàn)第一條語句不返回?cái)?shù)據(jù),而第二條語句返回一行,為什么?

LIKE匹配整個(gè)列,如果被匹配的文本在列值里出現(xiàn),LIKE將不會(huì)找到它,相應(yīng)的行也不被返回(除非使用通配符)。而REGEXP在列值內(nèi)進(jìn)行匹配,如果被匹配的文本在列值中出現(xiàn),REGEXP將會(huì)找到它,相應(yīng)的行將被返回。這是一個(gè)非常重要的差別。

那么,REGEXP能不能用來匹配整個(gè)列值(從而起與LIKE相同的作用)?答案是肯定的,使用^和$定位符(anchor)即可

匹配不區(qū)分大小寫 MySQL中的正則表達(dá)式匹配(自版本3.23.4后)不區(qū)分大小寫(即,大小寫都匹配)。為區(qū)分大小寫,可使用BINARY關(guān)鍵字,如WHERE prod_name REGEXP BINARY 'JetPack .000'。

2.2 進(jìn)行OR匹配

? 為搜索兩個(gè)串之一(或者為這個(gè)串,或者為另一個(gè)串),使用|,如下所示:

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '1000|2000'
ORDER BY prod_name;

輸出:

prod_name
JetPack 1000
JetPack 2000

分析:語句中使用了正則表達(dá)式1000|2000。|為正則表達(dá)式的OR操作。它表示匹配其中之一,因此1000和2000都匹配并返回。

? 使用|從功能上類似于在SELECT語句中使用OR語句,多個(gè)OR條件可并入單個(gè)正則表達(dá)式。

兩個(gè)以上的OR條件 可以給出兩個(gè)以上的OR條件。例如,'1000 | 2000 | 3000'將匹配1000或2000或3000。

2.3 匹配幾個(gè)字符之一

? 匹配任何單一字符。但是,如果你只想匹配特定的字符怎么辦?可以通過指定一組 [ 和 ] 括起來的字符來完成,如下所示:

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[123] Ton'
ORDER BY prod_name;

輸出:

prod_name
1 ton anvil
2 ton anvil

分析:這里使用了正則表達(dá)式[123] Ton[123]定義一組字符,它的意思是匹配1或2或3,因此,1 ton和2 ton都匹配且返回(沒有3 ton)。

? 正如所見,[ ]是另一種形式的OR語句。事實(shí)上,正則表達(dá)式[123] Ton[1|2|3] Ton的縮寫,也可以使用后者。但是,需要用 [ ]來定義OR語句查找什么。為更好地理解這一點(diǎn),請(qǐng)看下面的例子:

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '1|2|3 Ton'
ORDER BY prod_name;

輸出:

prod_name
1 ton anvil
2 ton anvil
JetPack 1000
JetPack 2000
TNT (1 stick)

分析:

? 這并不是期望的輸出。兩個(gè)要求的行被檢索出來,但還檢索出了另外3行。之所以這樣是由于MySQL假定你的意思是'1'或'2'或'3 ton'。除非把字符|括在一個(gè)集合中,否則它將應(yīng)用于整個(gè)串。
? 字符集合也可以被否定,即,它們將匹配除指定字符外的任何東西。為否定一個(gè)字符集,在集合的開始處放置一個(gè)即可。因此,盡管[123]匹配字符1、2或3,但【123】卻匹配除這些字符外的任何東西。

2.4 匹配范圍

? 集合可用來定義要匹配的一個(gè)或多個(gè)字符。例如,下面的集合將匹配數(shù)字0到9:

? [0123456789]

? 為簡(jiǎn)化這種類型的集合,可使用-來定義一個(gè)范圍。下面的式子功能等同于上述數(shù)字列表:

? [0-9]

? 范圍不限于完整的集合,[1-3]和[6-9]也是合法的范圍。此外,范圍不一定只是數(shù)值的,[a-z]匹配任意字母字符。

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[1-5] Ton'
ORDER BY prod_name;

輸出:

prod_name
.5 ton anvil
1 ton anvil
2 ton anvil

分析:這里使用正則表達(dá)式[1-5] Ton[1-5]定義了一個(gè)范圍,這個(gè)表達(dá)式意思是匹配1到5,因此返回3個(gè)匹配行。由于5 ton匹配,所以返回.5 ton。

2.5 匹配特殊字符

? 正則表達(dá)式語言由具有特定含義的特殊字符構(gòu)成。我們已經(jīng)看到.、[]、|和-等,還有其他一些字符。請(qǐng)問,如果你需要匹配這些字符,應(yīng)該怎么辦呢?例如,如果要找出包含.字符的值,怎樣搜索?請(qǐng)看下面的例子:

輸入:

SELECT vend_name
FROM vendors
WHERE vend_name REGEXP '.'
ORDER BY vend_name;

輸出:

vend_name
ACME
Anvils R Us
Furball Inc.
Jet Set
Jouets Et Ours
LT Supplies

分析:這并不是期望的輸出,.匹配任意字符,因此每個(gè)行都被檢索出來。

? 為了匹配特殊字符,必須用\ \為前導(dǎo)。\ \ -表示查找-,\ \ .表示查找.。

輸入:

SELECT vend_name
FROM vendors
WHERE vend_name REGEXP '\\.'
ORDER BY vend_name;

輸出:

vend_name
Furball Inc.

分析:這才是期望的輸出。\ \ .匹配.,所以只檢索出一行。這種處理就是所謂的轉(zhuǎn)義(escaping),正則表達(dá)式內(nèi)具有特殊意義的所有字符都必須以這種方式轉(zhuǎn)義。這包括.、|、[ ]以及迄今為止使用過的其他特殊字符。

? \ \也用來引用元字符(具有特殊含義的字符)

元字符 說明
\f 換頁
\n 換行
\r 回車
\t 制表
\v 縱向制表

匹配\ 為了匹配反斜杠(\)字符本身,需要使用\\。

\或\ ? 多數(shù)正則表達(dá)式實(shí)現(xiàn)使用單個(gè)反斜杠轉(zhuǎn)移特殊字符,以便能使用這些字符本身。但MySQL要求兩個(gè)反斜杠(MySQL自己解釋一個(gè),正則表達(dá)式解釋另一個(gè))。

2.6 匹配字符類

? 存在找出你自己經(jīng)常使用的數(shù)字、所有字母字符或所有數(shù)字字母字符等的匹配。為更方便工作,可以使用預(yù)定義的字符集,稱為字符類(character class)。表9-2列出字符類以及它們的含義。

說 明
[:alnum:] 任意字母和數(shù)字(同[a-zA-Z0-9])
[:alpha:] 任意字符(同[a-zA-Z])
[:blank:] 空格和制表(同[\ \t])
[:cntrl:] ASCII控制字符(ASCII 0到31和127)
[:digit:] 任意數(shù)字(同[0-9])
[:graph:] 與[:print:]相同,但不包括空格
[:lower:] 任意小寫字母(同[a-z])
[:print:] 任意可打印字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在內(nèi)的任意空白字符(同[\ \f \ \n \ \r \ \t \ \v])
[:upper:] 任意大寫字母(同[A-Z])
[:xdigit:] 任意十六進(jìn)制數(shù)字(同[a-fA-F0-9])

2.7 匹配多個(gè)實(shí)例

? 目前為止使用的所有正則表達(dá)式都試圖匹配單次出現(xiàn)。如果存在一個(gè)匹配,該行被檢索出來,如果不存在,檢索不出任何行。但有時(shí)需要對(duì)匹配的數(shù)目進(jìn)行更強(qiáng)的控制。例如,你可能需要尋找所有的數(shù),不管數(shù)中包含多少數(shù)字,或者你可能想尋找一個(gè)單詞并且還能夠適應(yīng)一個(gè)尾隨的s(如果存在),等等。

? 表 重復(fù)元字符

元 字 符 說 明
* 0個(gè)或多個(gè)匹配
+ 1個(gè)或多個(gè)匹配(等于{1,})
? 0個(gè)或1個(gè)匹配(等于{0,1})
{n} 指定數(shù)目的匹配
{n,} 不少于指定數(shù)目的匹配
{n,m} 匹配數(shù)目的范圍(m不超過255)

? 下面舉幾個(gè)例子。

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '\\([0-9] sticks?\\)'
ORDER BY prod_name;

輸出:

prod_name
TNT (1 stick)
TNT(5 sticks)

分析:正則表達(dá)式\([0-9] sticks?\)需要解說一下。\(匹配),[0-9]匹配任意數(shù)字(這個(gè)例子中為1和5),sticks?匹配stick和sticks(s后的?使s可選,因?yàn)?匹配它前面的任何字符的0次或1次出現(xiàn)),\)匹配)。沒有?,匹配stick和sticks會(huì)非常困難。

? 以下是另一個(gè)例子。這次我們打算匹配連在一起的4位數(shù)字:

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '[[:digit:]]{4}'
ORDER BY prod_name;

輸出:

prod_name
JetPack 1000
JetPack 2000

分析:如前所述,[:digit:]匹配任意數(shù)字,因而它為數(shù)字的一個(gè)集
合。{4}確切地要求它前面的字符(任意數(shù)字)出現(xiàn)4次,所以
[[:digit:]]{4}匹配連在一起的任意4位數(shù)字。

2.8 定位符

? 目前為止的所有例子都是匹配一個(gè)串中任意位置的文本。為了匹配特定位置的文本,需要使用表中的定位符。

? 表 重復(fù)元字符

元 字 符 說 明
^ 文本的開始
$ 文本的結(jié)尾
[[:<:]] 詞的開始
[[:>:]] 詞的結(jié)尾

? 下面舉幾個(gè)例子。

輸入:

SELECT prod_name
FROM products
WHERE prod_name REGEXP '^[0-9\\.]'
ORDER BY prod_name;

輸出:

prod_name
.5 ton anvil
1 ton anvi
2 ton anvil

分析:匹配串的開始。因此,[0-9\ \ .]只在.或任意數(shù)字為串中第一個(gè)字符時(shí)才匹配它們。沒有^,則還要多檢索出4個(gè)別的行(那些中間有數(shù)字的行)。

^的雙重用途 ^有兩種用法。在集合中(用[和]定義),用它來否定該集合,否則,用來指串的開始出。

使REGEXP起類似LIKE的作用 本章前面說過,LIKE和REGEXP的不同在于,LIKE匹配整個(gè)串而REGEXP匹配子串。利用定位符,通過用^開始每個(gè)表達(dá)式,用$結(jié)束每個(gè)表達(dá)式,可以使REGEXP的作用與LIKE一樣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容