正则中的一些高级查找
在正则中,拥有所谓的先行断言,后行断言,正向否定查找,反向否定查找等等使用方式,听起来令人头秃,他们分别表示什么含义?
首先,MDN 如是说明:
字符 | 含义 |
---|---|
(?:x) | 匹配x 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。 |
x(?=y) | 匹配x 仅仅当x 后面跟着y .这种叫做先行断言 |
(?<=y)x | 匹配x 仅当x 前面是y .这种叫做后行断言。 |
x(?!y) | 仅仅当x 后面不跟着y 时匹配x ,这被称为正向否定查找。 |
(?<!y)x | 仅仅当x 前面不是y 时匹配x ,这被称为反向否定查找。 |
仅看概念确实不太容易记住,下面举几个栗子了解一下它们每一种方式的使用场景,加深记忆。
非捕获分组?:
说到非捕获分组,肯定还有捕获分组。
捕获分组很简单,使用一个()
表示,在()
中的表示一个分组,使用()
会把每个分组里面的值保存起来,之后使用$1
、$2
等等这样的方式去引用不同分组。
但有的时候虽然使用括号了,但是不想让其捕获为分组怎么办,那就可以用到?:
非捕获分组。使用(?:exp)
表示这个分组是不需要被捕获的,所以里面的值也不会得到保存,你也无法引用。
举个栗子,假如有一个电话号码021-1234567
,如果我想匹配-
之后的数字,正则可以这样写。
'021-1234567'.replace(/\d{3}-(\d{7})/, '$1'); // 1234567
这里\d{7}
表示第一个分组,所以后面可以用$1
来直接匹配。假如我强行给\d{3}
加上分组,那么\d{3}
就成了第一个分组,而\d{7}
会变成第二个分组。
'021-1234567'.replace(/(\d{3})-(\d{7})/, '$2'); // 1234567
我们这个示例比较简单,可以明确知道\d{7}
是第二个分组,但是,有的时候某些分组并没有什么意义,况且,在复杂情况下,分组区分起来也会比较麻烦。如果还想让\d{7}
为第一分组,使用?:
来让其不参与捕获就可以了。
'021-1234567'.replace(/(?:\d{3})-(\d{7})/, '$1'); // 1234567
先行断言?=
语法
x(?=y)
即查找y
前面的x
。
如下栗子,查找hello world
中world
前面的hello
,找到的话,将hello
替换成whole
。
'hello world'.replace(/hello(?=\sworld)/, 'whole'); // whole world
'hello1 world'.replace(/hello(?=\sworld)/, 'whole'); // 输出:hello1 world,因为 world前不是hello,所以无法匹配到
比如千分位的转换,也可以使用到先行断言。
'123456789.2456'.replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
它的匹配方式如下图所示。
或者这样写也是可以的。
'1212123456789.1231'.replace(/\B(?=(\d{3})+\.)/g, ',');
首先\B
表示非单词边界,所以,这个正则的意思是匹配3n*数字 + 小数点
组合前面的非单词边界。
后行断言?<=
语法
(?<=y)x
即查找y
后面的x
。
还使用上面的示例,如果将hello world
替换为hello there
,使用后行断言,如下所示。
'hello world'.replace(/(?<=hello\s)world/, 'there'); // hello there
另一个例子
const reg = /(?<=\$)foo/g;
'$foo %foo foo'.replace(reg, 'bar'); // '$bar %foo foo'
示例中将$foo
全部替换成了$bar
。那么,如果不使用后行断言的话,是下面这样。
const reg = /(\$)foo/g;
'$foo %foo foo'.replace(reg, '$1bar'); // '$bar %foo foo'
嗯,还是后行断言看起来更加优雅一点。
正向否定查找?!
语法
x(?!y)
即当x
后面不是y
时,匹配x
。
'hello world, hello everyone, world hello'.replace(/hello(?!\sworld)/g, 'hi'); // hello world, hi everyone, world hi
这里查找hello
后面不是world
的hello
,那么除了第一个hello world
都符合。
反向否定查找?<!
语法
(?<!y)x
即当x
前面不是y
时,匹配x
。
'hello world, hi world, whole world'.replace(/(?<!hello\s)world/g, 'world2'); // hello world, hi world2, whole world2
查找world
前不是hello
的字符串,符合条件时,将world
替换成world2
。
- 本博客所有文章除特别声明外,均可转载和分享,转载请注明出处!
- 本文地址:https://www.leevii.com/?p=2935