环视是一种非捕获分组,它根据某个模式之前或之后的内容匹配其他模式。环视也称为零宽断言,匹配条件不会出现在匹配结果中。环视包括:正前瞻;反前瞻;正后顾;反后顾。
一、正前瞻
所谓正前瞻,是指肯定向后(从左到右)环视。例如要匹配单词 ancyent,且要求紧随其后的单词是 marinere。要达到这个目的,我们可以使用正前瞻。
代码语言:javascript复制mysql> set @r:='(?i)ancyent (?=marinere)';
Query OK, 0 rows affected (0.00 sec)
mysql> select id, regexp_substr(a,@r) from t_regexp where regexp_like(a,@r) and instr(a,char(10))=0;
---- ---------------------
| id | regexp_substr(a,@r) |
---- ---------------------
| 2 | ANCYENT |
| 7 | Ancyent |
| 9 | ancyent |
---- ---------------------
3 rows in set (0.00 sec)
(?i) 选项表示不区分大小写,regexp_substr 函数只返回了模式的第一部分 ancyent。环视模式 marinere 不会返回,因为环视是零宽断言,只匹配某个符合条件的位置。
二、反前瞻
反前瞻是对正前瞻的取反操作。这意味着要匹配某个模式时,需要在它后面找不到含有给定前瞻模式的内容。例如要匹配单词 ancyent,且要求紧随其后的单词不是 marinere。
代码语言:javascript复制mysql> insert into t_regexp (a) values ('ancyent man'),('Ancyent Man');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> set @r:='(?i)ancyent (?!marinere)';
Query OK, 0 rows affected (0.00 sec)
mysql> select id, regexp_substr(a,@r) from t_regexp where regexp_like(a,@r) and instr(a,char(10))=0;
---- ---------------------
| id | regexp_substr(a,@r) |
---- ---------------------
| 45 | ancyent |
| 46 | Ancyent |
---- ---------------------
2 rows in set (0.00 sec)
正则表达式中只有一个字符发生了变化:正前瞻的等号 = 变为反前瞻的感叹号 ! 。
三、正后顾
正后顾是指肯定向前(从右向左)环视,它与正前瞻方向相反。
代码语言:javascript复制mysql> set @r:='(?i)(?<=ancyent) marinere';
Query OK, 0 rows affected (0.00 sec)
mysql> select id, regexp_substr(a,@r) from t_regexp where regexp_like(a,@r) and instr(a,char(10))=0;
---- ---------------------
| id | regexp_substr(a,@r) |
---- ---------------------
| 2 | MARINERE |
| 7 | Marinere |
| 9 | Marinere |
---- ---------------------
3 rows in set (0.00 sec)
正后顾使用小于号 < ,表示后顾方向。regexp_substr 函数返回的是 marinere 而不是 ancyent。因为正后顾的模式是匹配条件,不会包含在匹配结果中。
四、反后顾
最后一种环视是反后顾,它会查看某个模式在从左至右的文本流的后面没有出现。同样,它有一个小于号 < 表示后顾方向。
代码语言:javascript复制mysql> insert into t_regexp (a) values ('The Marinere hath his will.'),('The bright-eyed marinere.');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> set @r:='(?i)(?<!ancyent) marinere';
Query OK, 0 rows affected (0.00 sec)
mysql> select id, regexp_substr(a,@r) from t_regexp where regexp_like(a,@r) and instr(a,char(10))=0;
---- ---------------------
| id | regexp_substr(a,@r) |
---- ---------------------
| 47 | Marinere |
| 48 | marinere |
---- ---------------------
2 rows in set (0.00 sec)
以上只是对环视的简单介绍,环视是现代正则表达式的一个重要特性。
五、例子
1. 为数值添加逗号
代码语言:javascript复制-- 单独数值
mysql> set @s:='1130733076480';
Query OK, 0 rows affected (0.00 sec)
mysql> set @r:='(?<=\d)(?=(?:\d\d\d) $)';
Query OK, 0 rows affected (0.00 sec)
mysql> select @s,regexp_replace(@s,@r,',');
--------------- ---------------------------
| @s | regexp_replace(@s,@r,',') |
--------------- ---------------------------
| 1130733076480 | 1,130,733,076,480 |
--------------- ---------------------------
1 row in set (0.00 sec)
-- 字符串中的数值
mysql> set @s:='The number 1130733076480 is so large!';
Query OK, 0 rows affected (0.00 sec)
mysql> set @r:='(?<=\d)(?=(?:\d\d\d) (?!\d))';
Query OK, 0 rows affected (0.00 sec)
mysql> select @s,regexp_replace(@s,@r,',');
--------------------------------------- -------------------------------------------
| @s | regexp_replace(@s,@r,',') |
--------------------------------------- -------------------------------------------
| The number 1130733076480 is so large! | The number 1,130,733,076,480 is so large! |
--------------------------------------- -------------------------------------------
1 row in set (0.00 sec)
-- 不使用逆序环视
mysql> set @r:='(\d)(?=(?:\d\d\d) (?!\d))';
Query OK, 0 rows affected (0.00 sec)
mysql> select @s,regexp_replace(@s,@r,'$1,');
--------------------------------------- -------------------------------------------
| @s | regexp_replace(@s,@r,'$1,') |
--------------------------------------- -------------------------------------------
| The number 1130733076480 is so large! | The number 1,130,733,076,480 is so large! |
--------------------------------------- -------------------------------------------
1 row in set (0.00 sec)