Mysql必知必會(4):使用正則表達式搜索(REGEXP)

本文主要介紹如何在Mysql中使用正則表達式進行搜索。html

正則表達式是一個很是大的內容,我會在以後專門寫博客介紹,這裏只是簡介一些經常使用匹配模式git

博客文章地址:http://weiya.me/item/59.html正則表達式

簡介

以前幾篇文章講解了各類各樣的過濾數據條件,經過這些條件,咱們已經可以知足平常開發中大部分的工做。但假設篩選條件更加複雜一點,好比你的老闆叫你從郵箱+手機號碼混合註冊的用戶中找出手機號碼註冊用戶,要給他們發送營銷短信。這時,以前的過濾方法就不太奏效。正則表達式搜索就派上大用場。sql

簡單來講,正則表達式就是用來匹配文本的特殊字符串。好比,從文本中提取電話號碼,帶數字的用戶名,或者提取某個特定格式的文本。數據庫

並且全部語言編輯器基本上都支持正則表達式,不得不說,正則表達式已經成爲開發過程當中強大而有力的工具。Mysql也不例外,那麼就開始正式學習這種特殊匹配方式。編程

本文所用到的Mysql表在文章最後的附錄。segmentfault

匹配字符串

匹配字符串是正則表達式最基礎的應用。咱們先給出一個例子:咱們從一個用戶表中查詢出名字中包含有100數字的用戶編程語言

圖片描述

SELECT * FROM my_user WHERE `name` REGEXP '100';

圖片描述

咱們獲得了用戶ID爲1的用戶:小紅100編輯器

該語句中不一樣於以前的語句,咱們使用REGEXP關鍵字表明後面爲正則表達式工具

這條語句看起來和LIKE語句特別類似,並且也是可使用LIKE語句來實現。那使用正則表達式的意義何在?

緣由很簡單。假設,我如今須要匹配不只僅是包含100數字的用戶,而是100,200,或者300,只要是整百的都須要匹配。或者說,我須要全部名字裏麪包含數字的,不管什麼數字。那麼使用LIKE來實現就會顯得十分的困難。而正則表達式就會顯得十分簡單。

SELECT * FROM my_user WHERE `name` REGEXP '.00'; // 匹配包含整百的名字,如100,200,300等等

表達式.00裏面的點,表明的任意字符。也就是不管是1仍是2仍是9,或者是字母什麼的均可以匹配,匹配任意。

圖片描述

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]'; // 匹配全部名字裏麪包含數字的用戶

圖片描述

是否是來的比LIKE簡單得多?上面的表達式,咱們在接下來就會詳細闡述。

正則和模糊查詢的區別

那麼咱們什麼狀況下應該使用LIKE?什麼狀況下又適合使用正則表達式查詢?

這裏咱們只須要記住LIKE查詢和正則查詢很是重要的差異便可。

先看兩個例子:

一、以前的一條語句

SELECT * FROM my_user WHERE `name` REGEXP '100';

圖片描述

二、LIKE查詢的實現

SELECT * FROM my_user WHERE `name` LIKE '100';

圖片描述

這裏咱們能夠清楚的看到二者的區別:正則表達式返回了一條記錄,而LIKE查詢沒有匹配到任何記錄

結論LIKE查詢匹配整個列,若是須要匹配的字符串(好比上面的100)包含在列中,那麼則沒法匹配成功。而正則匹配則能夠匹配列值內部的值,簡單來講就是它會從第一個字符開始日後匹配,只要匹配有一個成功那麼就會返回記錄。這是二者重要的區別。

那麼正則匹配是否也能夠匹配整個字符,固然能夠。不過須要涉及到另外的知識:定位符^$,下面將會做詳細解釋。

使用或查詢

若是正則表達式僅僅就是和LIKE有那麼一點兒的差異,也就不會有這麼高的地位了。下面纔是顯示身手的時候。

或查詢也叫OR查詢,是條件並列查詢的一種狀況。相似於編程語言裏面的if else只要有一個條件符合就會被匹配。

SELECT * FROM my_user WHERE `name` REGEXP '100|200';

圖片描述

上面的語句查詢了名字中包含了100或者200數字的用戶,就是說兩個數值只要匹配一個就能夠返回數據。

固然你也能夠給出多個或狀況,他們之間使用豎線分割便可。好比:100|200|300|400

使用或查詢的狀況,有點兒相似於SELECT中使用OR條件鏈接的狀況,你能夠把它們想象成併入了一個正則表達式。

匹配多個字符之一

正則匹配中有一種特殊的OR匹配。

SELECT * FROM my_user WHERE `name` REGEXP '[12]';

圖片描述

上面表達式中咱們使用了一個特殊的字符串[12],這個字符串的含義是:查詢名字中包含有數字1或者數字2的記錄,它是[1|2]的縮寫。

這種,使用方括號將字符串括起來的寫法,不管方括號內有多少字符串,其表達的含義都是匹配其中任意一個。

若是是[123456789]那麼就表明,匹配名字中包含1或2或3或4或5或6或7或8或9的任何一個記錄。

固然,字符串還能夠查詢被否認的狀況。[^12]若是在12以前加上一個^符號,那麼就表明除了1或2外的字符串。

SELECT * FROM my_user WHERE `name` REGEXP '[^12]';

圖片描述

說明:表中小紅100,雖然包含1,可是他包含了0。0不屬於1或者2,因此被匹配。

匹配一個範圍

看下咱們上面有個集合[123456789],若是每次咱們寫正則時候都這麼寫,那麼豈不是很麻煩。因此,咱們能夠簡化這種狀況,使用一個範圍[1-9]來代替這串字符串。若是是匹配全部數字,那麼就會包含0,咱們可使用[0-9]來表示。

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]';

圖片描述

這個表達式將會匹配出全部名字中包含數字的記錄。拆開理解就是,包含0或者1或者2...或者8或者9的記錄。

並且,這裏的範圍不只僅只能是數字,還能夠是字母。好比[a-z]就是表示從字母a到字母z的全部數字,26個字母。小寫完了,還有大寫[A-Z]。那麼咱們將其組合起來[0-9a-zA-Z]這個表達式就十分強大了,能夠表示包含數字,小寫字母,大寫字母的全部記錄。

SELECT * FROM my_user WHERE `name` REGEXP '[0-9a-zA-Z]';

圖片描述

因爲我名字裏面沒有包含字母的,因此結果和上面[0-9]相同。

匹配特殊字符串

咱們來看下下面的一條語句:

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]';

這個語句的意思是匹配名稱包含全部數字的記錄。0-9被方括號擴了起來,那麼假設我如今就須要匹配方闊號該如何處理?

這個時候就須要用到匹配特殊字符的知識。爲了匹配這些特殊的字符,咱們須要使用轉義功能,就是使用(雙反斜槓)做爲前導。假設咱們須要匹配經常使用特殊字符便可這麼寫:

\\[ 匹配左方括號
\\. 匹配點號
\\] 匹配右方括號
\\| 匹配豎線
\\\ 匹配反斜槓本身自己

依次類推,其餘特殊的字符串也可使用這麼方式處理。

雙反斜槓加上一些字母還能夠表示特殊的含義。

好比:

\\f 換頁
\\n 換行
\\r 回車
\\t 製表符
\\v 縱向製表符

在通常的編程語言中,轉義通常使用一個反斜線,在Mysql中爲何是兩個才行?緣由是:Mysql本身須要一個來識別,而後Mysql會將扣除了一個反斜槓的剩餘的部分徹底的交給正則表達式庫解釋,因此加起來就是兩個了。

使用預約義字符集

雖然正則表達式提供了一些很長表示方式的縮寫,好比[0-9]表示數字。[a-z]表示小寫字母。可是,有些時候仍是以爲複雜。因此,正則表達式還提供了一些預約義的字符類來方便咱們開發。

簡單來講,就像車牌使用蘇表明江蘇,而滬表明上海同樣。

咱們直接給出表直接參閱。

說明
[:alnum:] 任意數字和字母。至關於[a-zA-Z0-9]
[:alpha:] 任意字符。至關於[a-zA-z]
[:blank:] 空格和製表。至關於[(雙斜槓,segmentfault這裏雙斜槓打不出來)t]
[:cntrl:] ASCII控制字符(ASCII 0 到31和127)
[:digit:] 任意數字。至關於[0-9]
[:graph:] 與[:print:]相同,可是不包含空格
[:lower:] 任意的小寫字母。至關於[a-z]
[:print:] 任意可打印字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在內的任意空白字符。
[:upper:] 任意大寫字母。至關於[A-Z]
[:xdigit:] 任意十六進制的數字。至關於[a-fA-F0-9]

元字符

以前匹配的內容都是單詞匹配。就是若是匹配到一次就顯示,匹配不到就不顯示。可是,複雜的狀況有時候要求匹配不止一次。假設我須要匹配名字中包含2-3位數字的記錄。這個時候就須要使用一種特殊的元字符來修飾。

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]{2,3}';

圖片描述

是否是很是簡單?下面具體解釋它的用法。

拿出這個特殊字符串[0-9]{2,3},除去前面的[0-9]後面的{2,3}就被成爲重複元字符,它的做用就是使得前面的數字重複必定的次數。

元字符 做用
* 重複0次或者屢次
+ 重複一次或者屢次。至關於{1,}
? 重複0次或者1次
{n} 重複n次
{n,} 重複至少n次
{n,m} 重複n-m次
SELECT * FROM my_user WHERE `name` REGEXP '[0-9]*'; // 匹配名字包含或者不包含數字的記錄

圖片描述

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]{2,3}'; // 匹配名字內包含2位數或者3位數的記錄

圖片描述

定位元字符

除了以前的重複元字符,正則還有一種特殊的定位元字符

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

還記得以前區別LIKE和正則表達式的例子麼?LIKE是對整個字符串進行匹配,而正則是匹配到就能夠。

若是如今咱們須要在郵箱+手機號碼混合註冊的帳號中,挑選出手機號碼,那麼咱們就要對帳號進行從頭至尾的匹配。

好比手機號碼是11位數字,也就是說a11111111111不行,可是他又具有11個數字條件。

因此咱們要求從頭開始匹配到結尾,是11位數字。

SELECT * FROM my_user WHERE `name` REGEXP '^[0-9]{11}$';

爲了匹配到內容,我在數據庫內又加了一條記錄。

圖片描述

匹配結果

圖片描述

附錄:用戶表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for my_user
-- ----------------------------
DROP TABLE IF EXISTS `my_user`;
CREATE TABLE `my_user` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  `password` varchar(40) NOT NULL,
  `code` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of my_user
-- ----------------------------
INSERT INTO `my_user` VALUES ('1', '小紅100', '20', '7c4a8d09ca3762af61e59520943dc26494f8941b', '2arfs5dr6m');
INSERT INTO `my_user` VALUES ('2', '小明200', '19', '7c4a8d09ca3762af61e59520943dc26494f8941b', 'd59tg6dr5h');
INSERT INTO `my_user` VALUES ('3', '小黃350', '25', '7c4a8d09ca3762af61e59520943dc26494f8941b', 'w56tg9hjn3');
INSERT INTO `my_user` VALUES ('4', '小穎410', '25', '7c4a8d09ca3762af61e59520943dc26494f8941b', 'a5d23e9yh5');
INSERT INTO `my_user` VALUES ('5', '星空幻穎', '22', '7c4a8d09ca3762af61e59520943dc26494f8941b', '86d2sadft9');

星空幻穎,嚴穎

我的主頁:segmentfault

相關文章
相關標籤/搜索