1、在前面学习的过滤例子中允许用匹配、比较和通配操作符寻找数据。对于基本的的过滤(或者甚至是某些不那么基本的过滤),这样就足够了。但随着过滤条件的复杂性的增加,WHERE子句本身的复杂性也有必要的增加。这就是正则表达式变得有用的地方。正则表达式是用来匹配文本的特殊串(字符集合)。正则表达式用正则表达式语言来建立,与其他语言一样,正则表达式具有你必须学习的特殊语法和指令。
2、正则表达式的作用是匹配文本,将一个模式(正则表达式)与一个文本串进行比较。MYSQL用WHERE子句对正则表达式提供了初步的支持,允许你指定正则表达式过滤SELECT检索出的数据
例1:
mysql> SELECT platformName FROM roleinfo WHERE channelName REGEXP "pp" ORDER BY platformName;
+---------------+
| platformName |
+---------------+
| ainjigame_app |
| cinjigame |
+---------------+
1、上面例子的意思为:从roleinfo表中检索platformName列,返回channelName(任意位置)值中含有"pp"字段的所有行
2、在上面例子中除关键字LIKE被REGEXP替代外,这条语句看上去非常想LIKE语句。它告诉MYSQL:REGEXP后所跟的东西作为正则表达式处理
例2:
mysql> SELECT platformName,channelName,roleName FROM roleinfo WHERE roleName REGEXP ".100" ORDER BY platformName;
+---------------+---------------+----------+
| platformName | channelName | roleName |
+---------------+---------------+----------+
| ainjigame_app | bonjigame_bpp | Sbm_100 |
| xinjigame_app | xinjigame_100 | Sam_100 |
+---------------+---------------+----------+
1、这里使用了正则表达式".100",点"."是正则表达式语言中一个特殊字符。它表示表示匹配任意字符。当然这个特殊的例子也可以使用LIKE和通配符来完成
例2_1:
mysql> SELECT platformName,channelName,roleName FROM roleinfo WHERE roleName LIKE "%100" ORDER BY platformName;
+---------------+---------------+----------+
| platformName | channelName | roleName |
+---------------+---------------+----------+
| ainjigame_app | bonjigame_bpp | Sbm_100 |
| xinjigame_app | xinjigame_100 | Sam_100 |
+---------------+---------------+----------+
例3:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName LIKE "100";
Empty set (0.00 sec)
/*可以看到输出为空,即什么也没输出*/
例3_1:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "100";
+---------------+---------------+
| platformName | channelName |
+---------------+---------------+
| xinjigame_app | xinjigame_100 |
+---------------+---------------+
1 row in set (0.00 sec)
原因:Like匹配整个列,而正则表达式在是列值内进行匹配
注:
1、like匹配的是被匹配字段的整个值(未使用通配符和定位符时),或者说这个字段中的所有字符都必须被包含在like的匹配规则中,否则匹配失败不返回(除非使用通配符);而正则表达式REGEXP则是在值内进行匹配,只要被匹配的文本在列值中出现,就算是匹配成功,返回行。
2、关于大小写的区分:MySQL中正则表达式匹配(从版本3.23.4后)不区分大小写 。如果要区分大小写,应该使用BINARY关键字,如where post_name REGEXP BINARY 'Hello .000'
作用:为了搜索两个串之一(或者为这个串,或者为另一个串),使用“ | ”
例4:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "100|pp";
+---------------+---------------+
| platformName | channelName |
+---------------+---------------+
| xinjigame_app | xinjigame_100 |
| cinjigame | binjigamecvpp |
+---------------+---------------+
注:
1、语句中使用了正则表达式"100|pp"。"|"为正则表达式的OR操作符,它表示匹配其中之一。
2、使用"|"从功能上来看类似于在SELECT语句中使用OR语句,多个OR条件可并入单个正则表达式
3、可以给出两个以上的OR条件,例如"100|200|300"
匹配任何单一字符,可通过指定一组用中括号"[ ]"括起来的字符来完成
例5:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[123] tonanvil";
+---------------+-----------------+
| platformName | channelName |
+---------------+-----------------+
| xinjigame_app | 1 tonanvil |
| cinjigame | 3 tonanvil |
| ainjigame_app | 1000 3 tonanvil |
+---------------+-----------------+
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[123]tonanvil";
Empty set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[123]ton";
Empty set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[a|b|c]pp";
+---------------+---------------+
| platformName | channelName |
+---------------+---------------+
| cinjigame | ainjigame_bpp |
| ainjigame_app | ainjigame_app |
+---------------+---------------+
注:
1、这里使用了正则表达式"[123] tonanvil"和"[abc]pp",他们定义了一组字符。它的意思是匹配1或2或3(a或b或c)
2、正如所见,[ ]是另一种形式的OR语句。事实上"[123] tonanvil"是"[1|2|3] tonanvil"的缩写,但是必须使用[ ]来定义OR以确定查找什么,否则输出结果可能会与预期的不一致
例5_1:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "1|2|3 ton";
+---------------+----------------+
| platformName | channelName |
+---------------+----------------+
| xinjigame_app | 1 ton anvil |
| cinjigame | 3 ton anvil |
| ainjigame_app | ainjigame_1000 |
+---------------+----------------+
注:
1、在上面例子中,输出结果并不是我们所预期的(两个要求的行被检索出来,但还检索出了另外的行)。之所以会这样是由于MYSQL假定你的意思是"1"或"2"或"3 ton"。所以需要把字符"|"括在一个集合中,否则它将应用于整个串
2、^ 否定一个字符集合,将匹配除指定字符外的任何东西。[^123]将匹配除这些字符外的任何东西
例5_2:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[^123]ton";
+---------------+-------------+
| platformName | channelName |
+---------------+-------------+
| xinjigame_app | 1 ton anvil |
| cinjigame | 3 ton anvil |
| ainjigame_app | 4 ton anvil |
+---------------+-------------+
3 rows in set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[123] ton";
+---------------+-------------+
| platformName | channelName |
+---------------+-------------+
| xinjigame_app | 1 ton anvil |
| cinjigame | 3 ton anvil |
+---------------+-------------+
集合可用来定义要匹配的一个或多个字符:如[0123456789]或[0-9]将匹配数字0到9;范围不一定只是数值,[a-z]匹配任一字母字符
例6:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[1-3] ton";
+---------------+--------------+
| platformName | channelName |
+---------------+--------------+
| xinjigame_app | .1 ton anvil |
| cinjigame | 3 ton anvil |
+---------------+--------------+
注:
这里使用了正则表达式"[1-3] ton"。[1-3]定义了一个范围(包含边界值),这个表达式的意思为匹配1到3。由于1 ton匹配,所以返回了.1 ton anvil
正则表达式语言由具有特定含义的特殊字符构成,目前接触到的有.、[]、|、-等,还有一些其他字符,如果需要匹配这些特殊字符的话,就需要使用转义符(如匹配包含.字符的值)
例7:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP ".";
+---------------+--------------+
| platformName | channelName |
+---------------+--------------+
| xinjigame_app | .1 ton anvil |
| cinjigame | 3 ton anvil |
| ainjigame_app | 4 ton anvil |
+---------------+--------------+
注:
1、从上面例子的输出结果来看,输出结果并不是预期的,"."匹配任意字符,因此每个行都被检索出来
2、为了匹配特殊字符,就必须进行转义操作(\\),必须用"\\"为前导
例7_1:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "\\.";
+---------------+--------------+
| platformName | channelName |
+---------------+--------------+
| xinjigame_app | .1 ton anvil |
+---------------+--------------+
注:
1、"\\"也用来引用元字符(具有特殊含义的字符)
\\f | 换页 |
\\n | 换行 |
\\r | 回车 |
\\t | 制表 |
\\v | 纵向制表 |
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\\t\\r\\v]) |
[:upper:] | 任意大小字母(同 [A-Z]) |
[:xdigit:] | 任意十六进制数字(同 [a-fA-F0-9]) |
目前所使用的正则表达式都试图匹配单次出现。但有时需要对匹配的数目进行更强的控制。
元字符 |
说明 |
* | 0个或多个匹配 |
+ | 1个或多个匹配(等于 {1, }) |
? | 0个或1个匹配(等于 {0, 1}) |
{n} | 指定数目的匹配 |
{n, } | 不少于指定数目的匹配 |
{n ,m} | 匹配数目的范围(m不超过255) |
例8:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "\\([0-9] sticks?\\)";
+---------------+----------------+
| platformName | channelName |
+---------------+----------------+
| xinjigame_app | TNT (1 stick) |
| ainjigame_app | TNT (5 sticks) |
+---------------+----------------+
2 rows in set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "\\([0-9] sticks?)";
+---------------+----------------+
| platformName | channelName |
+---------------+----------------+
| xinjigame_app | TNT (1 stick) |
| ainjigame_app | TNT (5 sticks) |
+---------------+----------------+
注:
正则表达式"\\([0-9] sticks?\\)"。意思为:\\(匹配),[0-9]匹配任意数字,sticks?匹配stick和sticks(s后的?使s可选,因为?匹配它前面的任何字符的0次或1次出现),\\)匹配。没有?,匹配stick和sticks会非常困难
例9:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[[:digit:]]{4}";
+---------------+-------------+
| platformName | channelName |
+---------------+-------------+
| xinjigame_app | TNT 1000 |
| ainjigame_app | TNT 3000 |
+---------------+-------------+
2 rows in set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "[0-9][0-9][0-9][0-9]";
+---------------+-------------+
| platformName | channelName |
+---------------+-------------+
| xinjigame_app | TNT 1000 |
| ainjigame_app | TNT 3000 |
+---------------+-------------+
注:
[:digit:]匹配任意数字,因而它为数字的一个集合,{4}要求它前面的字符(任意数字)出现4次,所以[[:digit:]]{4}匹配连在一起的任意4位数字
目前所用到的正则表达式都是在文本内任意位置查找匹配的(未只用定位符时),在某些情况下我们就需要用到定位符了
^ | 文本的开始 |
$ | 文本的末尾 |
[[:<:]] | 词的开始 |
[[:>:]] | 词的结尾 |
例10:
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "^[0-9\\.]";
+---------------+--------------+
| platformName | channelName |
+---------------+--------------+
| xinjigame_app | .5 ton anvil |
| cinjigame | 3 ton anvil |
| ainjigame_app | 1 ton anvil |
+---------------+--------------+
3 rows in set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "^[\\.]";
+---------------+--------------+
| platformName | channelName |
+---------------+--------------+
| xinjigame_app | .5 ton anvil |
+---------------+--------------+
1 row in set (0.00 sec)
mysql> SELECT platformName,channelName FROM roleinfo WHERE channelName REGEXP "^[0-9]";
+---------------+-------------+
| platformName | channelName |
+---------------+-------------+
| cinjigame | 3 ton anvil |
| ainjigame_app | 1 ton anvil |
+---------------+-------------+
注:
1、^匹配串的开始。因此,"^[0-9\\.]"只在.或任意数字为串中第一个字符时才匹配他们。
2、^的双重用途:在集合中(用[ ]定义),用它来否定该集合。否则,用来指串的开始(^符合只有在[]内才是取反的意思)。
例11:
用示例,查找用户表中Email格式错误的用户记录:
ELECT *
FROM users
WHERE email NOT REGEXP '^[A-Z0-9._%-]+@[A-Z0-9.-]+.[A-Z]{2,4}$'