关于正则表达式,我收藏的一篇帖子讲得很好、很全,但是我没有学得很好,哈哈。
这里附上链接:https://blog.csdn.net/h610443955/article/details/81079439
(本文有部分直接借鉴的那篇文章的例子和文字)
1.正则表达式的创建
字面量:
let reg = /\d/g
对象形式:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g
以上两种创建的表达式的等价的。用对象形式创建时,接收两个参数,第一个是字符串,第二个是修饰符。同时对象形式创建正则时,需要转义时,需要使用两个\。建议:多用字面量形式,少用对象形式。
2.原子表[]
与选择符|
与元字符
(1) |
选择符
与逻辑运算中的“或”差不多。
let str = '23a34';console.log(str.match(/a|33/)) //['a'] 表示查找a 或者 33console.log(str.match(/ab|33/)) //null 表示查找ab 或者 33
(2) 原子表
[]就是纵向模糊匹配,纵向模糊指的是,一个正则匹配的字符串,具体到某一位字符时,它可以不是某个确定的字符,可以有多种可能。
其实现的方式是使用字符组。譬如[abc]
,表示该字符是可以字符“a”、“b”、“c”中的任何一个。
比如/a[123]b/
可以匹配如下三种字符串:"a1b"、"a2b"、"a3b"。测试如下:
var regex = /a[123]b/g;var string = "a0b a1b a2b a3b a4b";console.log( string.match(regex) );// => ["a1b", "a2b", "a3b"]
以上例子可以看出/[abc]/===/a|b|c/
,他们都是惰性的,即匹配到第一个后就停止匹配了。
排除字符组
纵向模糊匹配,还有一种情形就是,某位字符可以是任何东西,但就不能是"a"、"b"、"c"。
此时就是排除字符组(反义字符组)的概念。例如[^abc],表示是一个除"a"、"b"、"c"之外的任意一个字符。字符组的第一位放^(脱字符),表示求反的概念。
当然,也有相应的范围表示法。
(3) 元字符
是具有特殊含义的字符。
使用[\s\S]
和[\d\D]
、[\w\W]
可以匹配所有字符.
3.量词横向模糊匹配
横向模糊指的是,一个正则可匹配的字符串的长度不是固定的,可以是多种情况的。
其实现的方式是使用量词。譬如{m,n}
,表示连续出现最少m次,最多n次。
比如/ab{2,5}c/
表示匹配这样一个字符串:第一个字符是“a”,接下来是2到5个字符“b”,最后是字符“c”。测试如下:
var regex = /ab{2,5}c/g;var string = "abc abbc abbbc abbbbc abbbbbc abbbbbbc";console.log( string.match(regex) );// => ["abbc", "abbbc", "abbbbc", "abbbbbc"]
{m,m}
,表示出现m次。 {m,} 表示至少出现m次。 {m,n} 表示至少出现m次,最多出现n次。 ? 等价于{0,1}
,表示出现或者不出现。 + 等价于{1,}
,表示出现至少一次。 * 等价于{0,}
,表示出现任意次,有可能不出现。 3.贪婪匹配和惰性匹配
var regex = /\d{2,5}/g;var string = "123 1234 12345 123456";console.log( string.match(regex) );//["123", "1234", "12345", "12345"]
其中正则/\d{2,5}/,表示数字连续出现2到5次。会匹配2位、3位、4位、5位连续数字。
但是其是贪婪的,它会尽可能多的匹配。你能给我6个,我就要5个。你能给我3个,我就要3个。反正只要在能力范围内,越多越好。
我们知道有时贪婪不是一件好事。而惰性匹配,就是尽可能少的匹配:
let hd = 'hdddd';console.log(hd.match(/hd+/)); //['hdddd']console.log(hd.match(/hd+?/)); //['hd']console.log(hd.match(/hd*?/)); //['h']console.log(hd.match(/hd{1,3}?/)); //['hd']console.log(hd.match(/hd??/)); //['h']
其中/hd{1,3}?/
表示,虽然1到3次都行,当1个就够的时候,就不在往下尝试了。
通过在量词后面加个问号就能实现惰性匹配,因此所有惰性匹配情形如下:
{m,n}?
匹配m个{m,}?
匹配m个??
匹配0个+?
匹配1个*?
匹配0个
4.修饰符
g是全局查找
i是不区分大小写
m多行匹配多行匹配,只影响^
和$
,二者变成行的概念,即行开头和行结尾。
let hd = 'houdunren'console.log(hd.match(/u/)); //[ 'u', index: 2, input: 'houdunren', groups: undefined ]console.log(hd.match(/u/g)); //['u,'u']let hd = 'Hello World!'console.log(hd.match(/h/)); // nullconsole.log(hd.match(/h/i)); //[ 'H', index: 0, input: 'Hello World!', groups: undefined ]let str = "abcggab\nabcoab";console.log(str.match(/^abc/g)); //[ 'abc' ]console.log(str.match(/^abc/gm)); // 结果为:["abc", "abc"]console.log(str.match(/ab$/g)); //[ 'ab' ]console.log(str.match(/ab$/gm)); // 结果为:["ab", "ab"]
match
返回的一个数组,但是加没加修饰符g
返回值是有区别的,没有加g
,返回的数组第一个元素是整体匹配结果,然后是各个分组(括号里)匹配的内容,然后是匹配下标,最后是输入的文本。加g
后,返回的数组是全是匹配结果。
5.正则表达式位置匹配
正则表达式是匹配模式,要么匹配字符,要么匹配位置。
5-1. 什么是位置呢?
位置是相邻字符之间的位置。比如,下图中箭头所指的地方:
5-2. 如何匹配位置呢?
在ES5中,共有6个锚字符:
^
$
\b
\B
(?=p)
(?!p)
ES6新增了两个
(?<=)
(?<!)
(1) ^和$
^
(脱字符)匹配开头,在多行匹配中匹配行开头。
$
(美元符号)匹配结尾,在多行匹配中匹配行结尾。
let str = 'sdasdf324'console.log(str.match(/^[a-z]+/)); //匹配以字母开头的//[ 'sdasdf', index: 0, input: 'sdasdf324', groups: undefined ]console.log(str.match(/\d+$/)); //匹配以数字结尾的//[ '324', index: 6, input: 'sdasdf324', groups: undefined ]
(2)\b与\B
\b
是单词边界,具体就是\w
和\W
之间的位置,也包括\w
和^
之间的位置,也包括\w
和$
之间的位置。
\B
就是\b
的反面的意思,非单词边界。例如在字符串中所有位置中,扣掉\b
,剩下的都是\B
的。
(3) (?=p)和(?!p)、(?<=)和(?<!)断言
断言相当于if语句(?=)
一般是写在后面,表示判断后面是否符合,符合就匹配(表示后面是什么);(?<=)
一般写在前面,表示前面是否符合,符合就匹配(表示前面是什么)(?!)
一般写在后面,表示判断后面是否符合,不符合就匹配(表示后面不是什么);(?<!)
一般写在前面,表示前面是否符合,不符合就匹配(表示前面不是什么)
let users = ` 老板电话:12345678910 员工电话:98765432101`let reg = /(?<=\d{7})\d{4}/giusers = users.replace(reg, v => { return '*'.repeat(4)})console.log(users); // 老板电话:1234567**** 员工电话:9876543****
/(?<=\d{7})\d{4}/gi
的意思是存在七位数字后面的四位数字
6.原子组分组()
6.1 分组
我们知道/a+/
匹配连续出现的“a”,而要匹配连续出现的“ab”时,需要使用/(ab)+/
。
其中括号是提供分组功能,使量词+
作用于“ab”这个整体,测试如下:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g0
6.2 分支结构
而在多选分支结构(p1|p2)
中,此处括号的作用也是不言而喻的,提供了子表达式的所有可能。
比如,要匹配如下的字符串:
I love JavaScript I love Regular Expression
可以使用正则:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g1
如果去掉正则中的括号,即/^I love JavaScript|Regular Expression$/
,匹配字符串是"I love JavaScript"和"Regular Expression",当然这不是我们想要的。
6.3. 引用分组和反向引用和非捕获分组
这个大家就去看我分享的文档吧,那个写的挺详细的。哈哈
7.exec()和test()方法
前面的match()、search()、replace()
都是字符串的方法,但是exec()和test()
是正则的方法。
exec比match更强大 当正则没有g
时,使用match
返回的信息比较多。但是有g
后,就没有关键的信息index
了。
而exec
方法就能解决这个问题,它能接着上一次匹配后继续匹配:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g2
其中正则实例lastIndex
属性,表示下一次匹配开始的位置。
比如第一次匹配了“2017”,开始下标是0,共4个字符,因此这次匹配结束的位置是3,下一次开始匹配的位置是4。
从上述代码看出,在使用exec
时,经常需要配合使用while
循环:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g3
修饰符g,对exex和test的影响
而正则实例的两个方法exec
、test
,当正则是全局匹配时,每一次匹配完成后,都会修改lastIndex
。下面让我们以test
为例,看看你是否会迷糊:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g4
注意上面代码中的第三次调用test
,因为这一次尝试匹配,开始从下标lastIndex
即3位置处开始查找,自然就找不到了。
如果没有g
,自然都是从字符串第0个字符处开始尝试匹配:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g5
test整体匹配时需要使用^和$
这个相对容易理解,因为test
是看目标字符串中是否有子串匹配正则,即有部分匹配即可。
如果,要整体匹配,正则前后需要添加开头和结尾:
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g6
8.批量使用正则
对于复杂的字符串,我们可以批量使用正则进行匹配。
let reg = new RegExp('\\d','g');console.log(reg) ///\d/g7原文:https://juejin.cn/post/7098337533209575460