MySQL用正則表達式進行搜索

用正則表達式進行搜索

1.正則表達式介紹

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

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

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

2.使用MySQL正則表達式

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

2.1 基本字符匹配

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

輸入:

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

輸出:

prod_name
JetPack 1000

分析:

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

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

輸入:

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

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

LIKE與REGEXP

LIKEREGEXP之間有一個重要的差別。請看以下兩條語句:

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;

如果執行上述兩條語句,會發現第一條語句不返回數據,而第二條語句返回一行,為什么?

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

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

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

2.2 進行OR匹配

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

輸入:

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

輸出:

prod_name
JetPack 1000
JetPack 2000

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

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

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

2.3 匹配幾個字符之一

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

輸入:

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

輸出:

prod_name
1 ton anvil
2 ton anvil

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

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

輸入:

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)

分析:

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

2.4 匹配范圍

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

? [0123456789]

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

? [0-9]

? 范圍不限于完整的集合,[1-3]和[6-9]也是合法的范圍。此外,范圍不一定只是數值的,[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

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

2.5 匹配特殊字符

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

輸入:

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

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

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

輸入:

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

輸出:

vend_name
Furball Inc.

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

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

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

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

\或\ ? 多數正則表達式實現使用單個反斜杠轉移特殊字符,以便能使用這些字符本身。但MySQL要求兩個反斜杠(MySQL自己解釋一個,正則表達式解釋另一個)。

2.6 匹配字符類

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

說 明
[: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])

2.7 匹配多個實例

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

? 表 重復元字符

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

? 下面舉幾個例子。

輸入:

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

輸出:

prod_name
TNT (1 stick)
TNT(5 sticks)

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

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

輸入:

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

輸出:

prod_name
JetPack 1000
JetPack 2000

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

2.8 定位符

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

? 表 重復元字符

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

? 下面舉幾個例子。

輸入:

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\ \ .]只在.或任意數字為串中第一個字符時才匹配它們。沒有^,則還要多檢索出4個別的行(那些中間有數字的行)。

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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容