学习正则表达式 - 环视

2023-10-14 09:48:36 浏览数 (3)


        环视是一种非捕获分组,它根据某个模式之前或之后的内容匹配其他模式。环视也称为零宽断言,匹配条件不会出现在匹配结果中。环视包括:正前瞻;反前瞻;正后顾;反后顾。

一、正前瞻

        所谓正前瞻,是指肯定向后(从左到右)环视。例如要匹配单词 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)

0 人点赞