正则表达式的学习笔记

主要分为下面三个内容

  • 字符匹配
  • 位置匹配
  • 分组
  • 反向引用

字符匹配

字符的模糊匹配分为两种:横向模糊匹配纵向模糊匹配

横向模糊匹配

量词的表示方式

横向模糊匹配,一般用量词去实现,那么量词的表示方式有哪些?

量词 表示
{m,n} 最少 m 次,最多 n 次
{m} m 次
? 0 次或 1 次
+ 至少 1 次
* 0 次或多次
贪婪模式

所谓的贪婪模式,就是尽可能多的匹配,譬如abbbbb,用/ab+/g去匹配时,会匹配出abbbbb

惰性模式

惰性则是想法,就是尽可能少的匹配,上面的例子abbbbb,用/ab+?/g 去匹配时,则只会匹配到ab,所以我们如果要使用惰性模式的话,只需要在量词后面追加?即可。

纵向模糊匹配

字符组

字符组就是一组字符,在正则表达式中,它表示“在同一个位置可能出现的各种字符”,比如ab[cd][cd]就是字符组,可以匹配cd,普通字符组内的字符顺序和是否重复都不影响匹配,但在范围表示法中会字符顺序有要求。

范围表示法

比如我们要匹配从az26 个字母,很明显如果用普通字符组表示的话,那么正则表达式会很长,因此我们可以范围表示法表示:/[a-z]/,数字09也可以用/[0-9]/来表示。

排除型字符组

排除型字符组表示“在当前位置,匹配一个没有列出的字符”,可以用^托字符)来表示,比如在当前位置排除字母 a 到 z,用/[^a-z]/来表示,注意点:

  • 排除型字符组并不是表示在当前位置不要列出字符,这种理解是有问题的,因为这样的理解的话,则是暗示“这里不出现任何字符串也可以
  • ^托字符)必须紧跟[后面,否则表示普通字符^
字符的简写

正则表达式的解析引擎提供了一些简写形式:

简写 表示
\w 表示字母、数字、下划线的任意一个字符
\W \w的排除,表示字母、数字、下划线之外的任意一个字符
\d 表示数字09,d 是英文digit的简写
\D 表示非数字
\s 表示包括空格、制表符、换页符等空白字符的其中任意一个,即[ \t\r\n\v\f]
\S 表示非空字符
. 通配符,换行符、回车符、行分隔符和段分隔符除外,几乎表示任意字符。

多选分支

在正则中,可以用|分隔多个子表达式,表示的意思。比如匹配ab则可用/a|b/g表示。

位置匹配

正则表达式是基于匹配模式的,前面讲的是如何匹配字符,而这部分是讲如何匹配一个位置。在正则表达式引擎中,提供以下锚去匹配位置:^$\b\B(?=p)(?!p)(?<=p)(?<!p)

^与$

这两个锚很简单,分别开始位置与结束位置。比如需要去掉字符串' hello world '的首尾空字符:

1
2
var str = ' hello world ';
var str = str.replace(/^\s|\s$/g, '');

\b 与\B

\b表示单词的边界。比如字符串'hello world'\b去匹配处理:

1
2
var str = 'hello world';
var str = str.replace(/\b/g, '#'); // '#hello# #world#'

而\B 则是相反,它表示非单词边界,上面的例子如果用\B去匹配的话,得到的结果将是'h#e#l#l#o w#o#r#l#d'

(?=p)与(?!p)(先行断言)

(?=p)表示接下来字符是p的位置,比如字符'hello world'(?=l)去匹配处理:

1
2
var str = 'hello world';
var str = str.replace(/(?=l)/g, '#'); // 'he#l#lo wor#ld'

(?!p)则相反,表示接下来不是p的位置,上面的例子如果用(?!p),得到的结果将是'#h#ell#o# #w#o#rl#d#'

(?<=p)与(?<!p)(后行断言)

在 ES5 规范中,Javascript 是只支持先行断言,不支持后行断言,比如匹配l后面的位置,就需要用后行断言了,比如字符串'hello world'(?<=l)去匹配处理:

1
2
var str = 'hello world';
var str = str.replace(/(?<=l)/g, '#'); // 'hel#l#o worl#d'

类似的,(?<!p)表示匹配不是l的位置,上面的例子如果用(?<!p),得到的结果将是'#h#e#llo# #w#o#r#ld#'

分组

在正则中,实现表达式分组可以用括号()的方式,比如我想匹配单词ab,则可以用/(ab)+/g

1
2
var str = 'ababa abbb ababab';
str.match(/(ab)+/g); // ["abab", "ab", "ababab"]

分组引用

比如我们需要提取日期'2000-01-01'的年月日,分组引用就显得非常有用了,在正则中,每个()会生成一个分组(正则表达式引擎会开辟一个内存空间去存储匹配到的数据):

1
2
var str = `2000-01-01`;
var matches = /(\d{4})-(\d{2})-\1/g.exec(str); // ["2000-01-01", "2000", "01", "01"]

最后只需要按照分组编号取值即可,比如年月日分别:matches[1]matches[2]matches[3],或者用构造函数RegExp的静态方法$1$2$3

反向引用

反向引用表示引用之前出现的分组。比如我们需要实现判断以下格式的日期是否合法:

1
2
3
2016-06-12
2016/06/12
2016.06.12

我们先用以下正则去匹配:

1
2
3
4
5
6
7
8
9
var str1 = '2016-06-12';
var str2 = '2016/06/12';
var str3 = '2016.06.12';
var str4 = '2016/06.12';
var regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/g;
regex.test(str1); // true
regex.test(str2); // true
regex.test(str3); // true
regex.test(str4); // true

显然的,str4的结果不是我们预期的,分别符-/.需要成对出现,这时候就需要用到反向引用了,上面的正则表达式可以改成:

1
2
3
4
5
6
7
8
9
var str1 = '2016-06-12';
var str2 = '2016/06/12';
var str3 = '2016.06.12';
var str4 = '2016/06.12';
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/g;
regex.test(str1); // true
regex.test(str2); // true
regex.test(str3); // true
regex.test(str4); // false

其中\1就是反向引用,表示引用第一个分组(-|\/|\.)

[本文谢绝转载,谢谢]

粤ICP备2022084378号