字符组有时也被称为方括号表达式(bracketed expression)。字符组有助于匹配特定字符或者特定的字符序列。它们可以像字符简写式那样代表一大批字符,比如 d 匹配的字符与 [0-9] 所匹配的字符一样。但字符组更有针对性,因此用途比简写式更广。下面是一些字符组简单例子。
- 匹配英文元音字母:[aeiou]
- 匹配某个范围的字符:[a-z]、[a-f]
- 匹配一个范围的数字:[0-9]、[3-6]
- 匹配 10~19 的偶数:b[1][24680]b
- 匹配 0~99 的偶数:b[24680]b|b[1-9][24680]b
- 匹配空格和单词字符:[_a-zA-Z0-9 tnr] 或 [ws]
一、匹配十六进制数
需求为找出含有十六进制数字的字符串。十六进制数字由 0-9、A-F 十六个字符构成,并且假设有三种表示形式:
- 以 0x 或 0X 为前缀。
- 以 $ 为前缀。
- 以 h 或 H 为后缀。
1. 生成测试数据
代码语言:javascript复制set @x:=conv(54321,10,16);
insert into t_regexp(a) values
(concat('a 0x',@x,' z')),(concat('a 0X',@x,' z')),(concat('a $',@x,' z')),(concat('a $',lower(@x),' z')),(concat('a ',@x,'h z')),(concat('a ',@x,'H z')),
(concat('a 0x',@x,'h z')),(concat('a $',@x,'h z')),(concat('a $0x',@x,'h z')),(concat('a 0x$',@x,'h z')),(concat('a ^0x',@x,' z'));
2. 编写正则表达式
代码语言:javascript复制s(?i)(((0x|$)[a-fd] )|([a-fd] h))s
3. 使用regexp函数查询验证
代码语言:javascript复制mysql> select a from t_regexp where a regexp '\s(?i)(((0x|\$)[a-f\d] )|([a-f\d] h))\s';
------------
| a |
------------
| a 0xD431 z |
| a 0XD431 z |
| a $D431 z |
| a $d431 z |
| a D431h z |
| a D431H z |
------------
6 rows in set (0.00 sec)
可以看到查询结果包含了所有符合规则的十六进制数。
4. 分析与知识点
- (?i) 修饰符表示后面分组不区分大小写。
- ((0x|\)[a-f\d] ) 分组表示以 0x 或 开始后跟一个或多个十六进制字符。
- ([a-f\d] h) 分组表示一个或多个十六进制字符,并以 h 结尾。
- 用选择操作符 | 分别匹配两种情况。
- 正则表达式首尾的 s 表示只匹配整个十六进制数。注意这里不能使用 b ,因为 b 会将 ^、$ 等符号作为分隔符的一部分,产生错误的结果:
mysql> select a from t_regexp where a regexp '\b(?i)(((0x|\$)[a-f\d] )|([a-f\d] h))\b';
--------------
| a |
--------------
| a 0xD431 z |
| a 0XD431 z |
| a D431h z |
| a D431H z |
| a $D431h z |
| a 0x$D431h z |
| a ^0xD431 z |
--------------
7 rows in set (0.00 sec)
二、字符组取反
对字符组取反会匹配与字符组内容不匹配的字符。比如,如果不想匹配元音字符,可以这样写:[^aeiou]。该字符组起始位置的脱字符(^)的意义就是:“不匹配这些字符”。脱字符必须出现在起始位置。
三、并集与差集
字符组可以像集合那样操作。不是所有的实现程序都支持这项功能,但 MySQL 支持该功能。
1. 匹配并集
代码语言:javascript复制mysql> set @r:='[0-3[6-9]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select '1' regexp @r,'5' regexp @r, '8' regexp @rG
*************************** 1. row ***************************
'1' regexp @r: 1
'5' regexp @r: 0
'8' regexp @r: 1
1 row in set (0.00 sec)
正则表达式处理器会匹配0到3之间的数字或者6到9之间的数字。
2. 匹配差集
代码语言:javascript复制mysql> set @r:='[a-z&&[^m-r]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select 'a' regexp @r, 'b' regexp @r, 's' regexp @r, 'z' regexp @r, 'l' regexp @r, 'm' regexp @r, 'r' regexp @r, 'n' regexp @rG
*************************** 1. row ***************************
'a' regexp @r: 1
'b' regexp @r: 1
's' regexp @r: 1
'z' regexp @r: 1
'l' regexp @r: 1
'm' regexp @r: 0
'r' regexp @r: 0
'n' regexp @r: 0
1 row in set (0.00 sec)
这匹配a到z之间的字符,但其中m到r之间的字符除外。
四、POSIX字符组
POSIX(Portable Operating System Interface,可移植操作系统接口)是 IEEE 维护的一系列标准,其中包含了一个正则表达式标准(ISO/IEC/IEEE 9945:2009)。该标准提供了一套命名的字符组,其形式为:[[:xxxx:]]。
1. 匹配字母及数字
代码语言:javascript复制mysql> set @r='[[:alnum:]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select '0' regexp @r, '9' regexp @r, 'a' regexp @r, 'A' regexp @r, 'z' regexp @r, 'Z' regexp @r, 'n' regexp @r, '\n' regexp @rG
*************************** 1. row ***************************
'0' regexp @r: 1
'9' regexp @r: 1
'a' regexp @r: 1
'A' regexp @r: 1
'z' regexp @r: 1
'Z' regexp @r: 1
'n' regexp @r: 0
'\n' regexp @r: 1
1 row in set (0.03 sec)
[[:alnum:]] 与简写式 w 等价。
2. 匹配字母
代码语言:javascript复制mysql> set @r:='[[:alpha:]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select 'a' regexp @r, 'A' regexp @r, 'z' regexp @r, 'Z' regexp @r, '0' regexp @r, '9' regexp @rG
*************************** 1. row ***************************
'a' regexp @r: 1
'A' regexp @r: 1
'z' regexp @r: 1
'Z' regexp @r: 1
'0' regexp @r: 0
'9' regexp @r: 0
1 row in set (0.02 sec)
3. 匹配非字母字符
代码语言:javascript复制mysql> set @r:='[[:^alpha:]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select 'a' regexp @r, 'A' regexp @r, 'z' regexp @r, 'Z' regexp @r, '0' regexp @r, '9' regexp @rG
*************************** 1. row ***************************
'a' regexp @r: 0
'A' regexp @r: 0
'z' regexp @r: 0
'Z' regexp @r: 0
'0' regexp @r: 1
'9' regexp @r: 1
1 row in set (0.11 sec)
4. 匹配空格
代码语言:javascript复制mysql> set @r:='[[:space:]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select ' ' regexp @r, 't' regexp @r, 'n' regexp @r, 'r' regexp @r;
--------------- ---------------- ---------------- ----------------
| ' ' regexp @r | 't' regexp @r | 'n' regexp @r | 'r' regexp @r |
--------------- ---------------- ---------------- ----------------
| 1 | 1 | 1 | 1 |
--------------- ---------------- ---------------- ----------------
1 row in set (0.00 sec)
5. 匹配空白字符
代码语言:javascript复制mysql> set @r:='[[:blank:]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select ' ' regexp @r, 't' regexp @r, 'n' regexp @r, 'r' regexp @r;
--------------- ---------------- ---------------- ----------------
| ' ' regexp @r | 't' regexp @r | 'n' regexp @r | 'r' regexp @r |
--------------- ---------------- ---------------- ----------------
| 1 | 1 | 0 | 0 |
--------------- ---------------- ---------------- ----------------
1 row in set (0.00 sec)
与 [[:space:]] 不同,[[:blank:]] 不包括回车、换行符。
6. 匹配ASCII范围内的字符
代码语言:javascript复制mysql> set @r:='[[:ascii:]]';
Query OK, 0 rows affected (0.00 sec)
mysql> select char(0) regexp @r, char(1) regexp @r, char(127) regexp @r, char(128) regexp @r;
------------------- ------------------- --------------------- ---------------------
| char(0) regexp @r | char(1) regexp @r | char(127) regexp @r | char(128) regexp @r |
------------------- ------------------- --------------------- ---------------------
| 1 | 1 | 1 | 0 |
------------------- ------------------- --------------------- ---------------------
1 row in set (0.00 sec)
[[:ascii:]] 匹配 ascii码 0~127的字符。
下表所示为POSIX字符组。
字符组 | 描述 |
---|---|
[[:alnum:]] | 匹配字母或数字 |
[[:alpha:]] | 匹配字母 |
[[:ascii:]] | 匹配ASCII字符(共128个) |
[[:blank:]] | 匹配空白字符 |
[[:ctrl:]] | 匹配控制字符 |
[[:digit:]] | 匹配数字 |
[[:graph:]] | 匹配图形字符 |
[[:lower:]] | 匹配小写字符 |
[[:print:]] | 匹配可打印字符 |
[[:punct:]] | 匹配标点符号 |
[[:space:]] | 匹配空格字符 |
[[:upper:]] | 匹配大写字符 |
[[:word:]] | 匹配单词字符 |
[[:xdigit:]] | 匹配十六进制数字 |