004-正規表示式
MySQL利用REGEXP命令提供給使用者擴充套件的正規表示式功能,熟悉掌握REGEXP的功能可以使模式匹配工作事半功倍。
表示式 說明
^ 字串開始處進行匹配(以“後面字串”開始匹配字元)
$ 字串結尾處進行匹配(以“前面字串”結尾匹配字元)
. 匹配任意單個字元,包括換行符。
[…] 匹配括號內的任意字元
[^…] 不匹配出括號內的任意字元
a* 匹配零個或多個a(包括空串)同a?
a? 匹配零個或多個a(包括空串)同a*
a+ 匹配1個或多個a(不包括空串)
a1|a2 匹配a1或a2
a{m} 匹配M個a
a{m,} 匹配m個或更多個a
a{m,n} 匹配m到n個a
a(,n) 匹配0到n個a,已經放棄。
(…) 將模式元素組成單一元素
示例:不區分大小寫。跟字符集相關。collation_connection utf8mb4_0900_ai_ci ci不區分大小寫。
加上binary表示改表示式強制區分大小寫。
(1)以..開頭,以..結尾
SELECT * FROM `emp` where ename rlike '^A';
等同
SELECT * FROM `emp` where ename regexp '^A';
等同
SELECT * FROM `emp` where ename regexp '^a';
^,$,. 在字串開始處匹配字元,匹配成功返回1,否則為0.
select 'asdf' regexp 'f$';
select 'asdf' regexp '^a';
select 'asdf' regexp 'a.';
select 'asdf' regexp '.';
(2)匹配單個字元。
. 匹配任意單個字元。binary使用二進位制匹配,區分大小寫
SELECT * FROM `emp` where ename regexp '.c';
SELECT * FROM `emp` where ename regexp binary 'c.';
(3)匹配指定任意字元,排除指定字串。
[…] 匹配中間任一字元,[^…] 不匹配任一字元。兩個其他字元之間的-字元形成一個範圍
SELECT * FROM `emp` where ename regexp '[3f]';
匹配到返回1,未匹配到返回0.
select 'er11' regexp '[r1213]';
SELECT * FROM `emp` where ename regexp '[a-d]';
注意:[^..] 這裡除了[]中的串,其他都匹配出來,[]中的字串是完整匹配,而不是任一字元。
SELECT * FROM `emp` where ename regexp '[^ALLEN]';
匹配多個:
SELECT * FROM `emp` where ename regexp '[^ALLEN|WARD]';
SELECT * FROM `emp` where ename regexp '[^a-d]'; 這裡只排除了一個字串"abcd",只有沒有這樣序列的字串,都檢索出來。
但是:
select 'asdf' regexp '[^sdf]'; 1 沒有匹配到,返回1,
select 'asdf' regexp '[^asdf]'; 0 匹配了,所以返回0.
(4)任意匹配
a* = a? 匹配任意各個任意字元(包括0個,空串)。
a+ 匹配1個或多個,不包括空串
select 'asdf' regexp 'a?';
select 'asdf' regexp 'a*';
select 'asdf' regexp 'a+';
三個一致。
select 'a sdf' regexp 'a?s';
select 'a\nsdf' regexp 'a*s';
select 'a sdf' regexp 'a+s';
最後一個沒匹配上。它只能匹配as,aas,aaas....
而上面2個,能匹配a s, s,adbfs,dbfs.....
SELECT * FROM `emp` where ename regexp 'c*t';
能夠匹配c..t的,也能匹配帶t字串。
SELECT * FROM `emp` where ename regexp 'c*';
能匹配到全部14條,因為c*表示0個或多個,也就是說沒有c也可以匹配,= 直接匹配*或者?
換成SELECT * FROM `emp` where ename regexp binary 'c.';
帶c都能匹配,只有c結尾的無法匹配。
select 'a sdfc' regexp 'c.';
(5)指定匹配字元個數。
select 'aaaffc' regexp 'a{2}'; 1
select 'aaaffc' regexp 'a{3}'; 1
select 'aaaffc' regexp 'a{1,}'; 1
select 'aaaffc' regexp 'a{,3}'; 語法錯誤
select 'aaaffc' regexp 'a{1,3}'; 1
a{1,3}表示1-3個,包含邊界值。相當於>=1 <=3.
a* a? 可以寫成 a{0,}
a+ 可以寫成 a{1,}
SELECT * FROM `emp` where ename regexp 't{2}';
(…)將模式元素組成單一元素
將括號裡面的字元做一個整體進行匹配,如果多個字元,只匹配上一個,返回0,必須都匹配上,也就是說匹配括號內的字串。
當子串在字串的開頭或結尾的時候。(...)可以改寫成:
SELECT * FROM `emp` where ename regexp '^sc'; SCOTT
SELECT * FROM `emp` where ename regexp 'tt$'; SCOTT
當一個字串,需要匹配的子串,在中間,也可以這樣。
SELECT * FROM `emp` where ename regexp 'co'; SCOTT
正例:
SELECT 'pihhhpi' REGEXP '^(pi)*$'; 0
SELECT 'pipi' REGEXP '^(pi)*$'; 1
SELECT 'pi' REGEXP '^(pi)*$'; 1
SELECT 'pip' REGEXP '^(pi)*$'; 0
^(pi)*$
表示,以pi為整體 開頭,*不再表示任意個任意字元,而是匹配1+個pi,以pi結尾。
可以改寫成: ^(pi){1,}(pi)$ 語法稍顯麻煩。而且無法匹配"pi" 這個單字串。
因此這就是(...)的適用場景。
=============================正規表示式在日常中的應用 ===============================
(1)過濾163郵箱
例如我們需要過濾出,使用163郵箱的使用者資訊。
同時 要求: @和#都是合法的郵件使用者名稱與域名分隔符。yy#163,com 也算163的郵箱
,和.都是合法的域名與域名字尾分隔符。yy@163,com 也算163的郵箱
方案1:like
select * from user_info where email like '%@163.com' or like '%@163,com' or like '%#163,com' or like '%#163.com'
方案二:正則
select * from user_info where email regexp '.*[@#]163[.,]com$'
(2)隨機抽取test表資料的樣本
oracle中用DBMS_RANDOM,MySQL中使用RAND()函式來實現,可以利用這個函式與order by 一起使用,來完成隨機抽取某些行的功能。其實就是order by rand()能夠把資料隨機排序。