JS正则表达式学习三

继续上文,先贴原文地址

之前的部分学习了字符匹配和位置匹配,可以说涵盖了很多日常开发中会用到的知识点。接下来要学习的是我觉得正则中很神奇的一部分,那就是括号的使用

就像文章中说的,对括号的使用是否得心应手,是衡量对正则的掌握水平的侧面标准。确实是,再正则中使用括号会有很好的效果,能起到很好的功能作用。

常用的是它的分组功能,顾名思义就是将一组内容作为一个整体。比如 /(ab)+/g 就表示 ab 这个整体连续出现。如果不写括号会被认为是 b 的连续出现。除此之外还有分支功能,如 (x|y) 表示既可能是 x ,也可能是 y。这些都是比较常见的用法,接下来学习比较少见到,但是却能高效解决问题的用法。

1. 引用分组

这是很重要的一个功能,常常用来作为数据的提取以及替换的操作,将需要操作的部分用括号括起来之后,就可以提取或者替换。

比如常见的日期提取,这里贴上原文中的一段代码:

1
2
3
4
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
console.log( string.match(regex) );
// => ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"]

可以看到,使用 match() 方法可以将正则需要提取的内容拿出来。也可以使用 exec()

1
2
3
4
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
console.log( regex.exec(string) );
// => ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"]

除此之外还可以使用 $1$9 来获取,这是我觉得这块内容最有用的地方,接下来就会用到。

除了匹配之外,替换才是更常用的,比如我们常见的日期替换,要把 2018-10-11 换成 2018/10/11。很多时候我们都是把 - 直接替换成 / ,但是如果要换成 10/11/2018 的时候,就不能在用这个办法,所以接下来的才是更好的方法。

1
2
3
4
5
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2018-10-11";
var result = string.replace(regex, "$2/$3/$1");
console.log(result);
// => "10/11/2018"

可以看到从左到右三个括号依次包括的是 年、月、日 。然后通过 $1$2$3 分别指代,然后我们可以排列成我们想要的形式了。

2. 反向引用

这在业务代码中几乎没有见到过,之前也完全没听说过正则还可以这样用,大开眼界!

反向引用指的是可以在正则本身里面引用之前的分组,即前面出现了某个字符,后面可以通过反向引用来拿到这个字符,然后进行想要的操作。这里继续贴上原文中的代码例子(自己想不出例子来,😓):

1
2
3
4
5
6
7
8
9
var regex = /\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // true

如上所示,想要匹配 2016-06-122017/06/122017.06.12 这三种形式的日期,我们可能会写出示例中的代码,可以看到确实是可以匹配的,但是最后一种情况 2016-06/12 也会被匹配。因为没法对前后出现的内容做同步,前面使用的是 - ,但是没办法保证后面使用的同样也是 -。反向引用可以解决这个问题:

1
2
3
4
5
6
7
8
9
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/;
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // false

可以看到,使用了 \1 来引用之前括号中的内容,这样就会使得前后是一致的,所以 2016-06/12 这种情况是不能够通过的。

有了 \1 ,那么相应的 \2 \3 \4 也就很好理解了,但是这种情况下会出现括号嵌套的情况,这种情况下以左括号出现的先后顺序为准,比如:

1
2
3
4
5
6
7
var regex = /^((\d)(\d(\d)))\1\2\3\4$/;
var string = "1231231233";
console.log( regex.test(string) ); // true
console.log( RegExp.$1 ); // 123
console.log( RegExp.$2 ); // 1
console.log( RegExp.$3 ); // 23
console.log( RegExp.$4 ); // 3

如果引用的分组不存在,那么 \1 就是简单的对字符 1 做了转义。

3. 非捕获分组

之前的使用都是使用括号来匹配数据,但是如果不想要这些功能,只想安安静静的做一个普通的括号呢,也有办法。可以使用非捕获分组 (?:p) 。这样就不会被引用了!

 Comments