身为一个前端不会正则,不羞愧吗?不会写至少看得懂,改的动吧!
看完这篇正则你就离精通正则不远了,抓紧卷起来!!
创建正则的两种方式
/pig/ //正则字面量
const reg = new RegExp('pig','g') // 使用new一个对象的方式创建正则
or
const r = '\\d'
const reg2 = new RegExp(r,'g')
复制代码
语法
元字符
\d
、0-9
代表数字,其中0-9是代表的匹配0到9之间的数字,当然也可以2-8等等, \D 代表除了数字以外的 其余的都是大写跟小写的都是相反的
\w
代表字母数字下换线 \W
同理
\s
代表空白符 空格、制表符、换页符啥的 \S 同理
/\s/.test('\n') // true
[a-z]
小写字母a-z [A-Z]
大写字母[A-Za-z]
大小写字母
.
代表除了换行符以外的任意字符
限定符
其实就是出现多少次才能满足匹配
+
至少出现一次 比如re+ 能匹配 re、ree等 不能匹配r,e至少得出现一次
*
0次或多次 比如re* 能匹配 r、re、ree等都能匹配,因为是0次或多次
?
0次或一次 同理如上(结合使用还能禁止贪婪,贪婪下面讲到)
{n}
出现n次 /p{2}/
就是匹配 pp,连续出现两次的p
{n,}
至少出现n次
{n,m}
出现n到m次
限定边界
^
匹配开头的位置 这里位置是什么意思?
$
匹配结尾的位置
这样一个需求,我先要去校验一个字符串长度为3的字符串pig。
/pig/.test('pig') // true
乍一眼看上去没啥问题
/pig/.test('pigg') // true
发现pigg也可以,但是我想要的就是长度为3的pig,这里就需要加上开头^、结尾$。
/^pig$/.test('pigg') // false
选择符
|
匹配左右两边的表达式(不是左右两边的单个字符),如我要匹配
原子组
()
原子组就是括号是一个整体
我要匹配'2021-05-16'
or'2021\05\16
,'2021\05-16'
这种不符合
const str = '2021-05-16'
const str2 = '2021/05/16'
/\d{4}([\/-])\d{2}\1\d{2}/.test(str)
\1的意思就是从头开始数第一个原子组匹配的内容就是([\/-])
以此类推\2就是第二个......
复制代码
这里来一道正则题,如下
匹配:
aaaa-aa=aa
aaaaa-a=aaaa
aaa-a=aa
aaaa-aaa=a
不匹配:
aaaa-a=aa
a-aaa=aa
aaa-aaa=
a-=a
复制代码
结尾有答案
这里讲一下match
方法,match返回一个数组,0为匹配文本,1、2、3…匹配的为原子组
'pig'.match(/p((i)(g))/) // ["pig","ig","i","g"]
复制代码
有时候会这样
'www.xxx.cn'.match(/\w+\.\w+\.(cn|com|org)/) // ["www.xxx.cn","cn"]
很明显这里不需要保留后面的原子表就是cn的部分,可以这样
'www.xxx.cn'.match(/\w+\.\w+\.(?:cn|com|org)/) // ["www.xxx.cn"]
'pigpig'.match(/(pig)+/) // ["pigpig","pig"]
复制代码
原子组别名,match方法还有个属性叫:groups
取出name键值对,存入一个对象。
const str = 'name=pig'
str.match(/(?<key>.+)=(?<value>.+)/)
// 结果的groups {
key: "name"
value: "pig"
}
复制代码
原子表
[]
上面讲到了选择符 |,当我想要匹配一个字符是p 或 i 或 g时可以这样写,/p|i|g/
,当情况更多的时候就可以选择使用原子表,如/[pig]/
,这个的意思就是字符是原子表中的任意一个即满足当前的正则。
其实原子表就是里面写了啥匹配啥,当原子表开头写了^就是匹配除了原子表内的字符,/[^pig]/
,这个就是匹配除了pig这三个字符以外的字符。([.+]
这里面匹配的就是字符串.或者+)
/[\d]/ //匹配数字
/[^\d]/ //匹配除了数字以外的 等同于 \D
/[^\dpig]/ //匹配除了数字pig这三个字符以外的
const str = `
p
i g
` // 捕获里面的所有字符串
str.match(/[^\s]+/g) // ["p", "i", "g"]
复制代码
转义
\
这里单独讲一下转义字符在正则中的用法,两种方式创建的正则都分别讲一下,一个这样的需求我想匹配一下:1.23这种包含小数点的正数字,按照上面讲的字符写一下。
/^\d+.\d+$/.test('1.23') // true 好像没问题,让我们把.换成别的试试
/^\d+.\d+$/.test('1@23') // true 怎么回事??? 写的好像没问题
复制代码
这里主要的问题就是正则中的.代表的是任意字符就是我上面写的那个,那我要匹配的就是.而不是它在正则中代表的任意字符怎么弄,\ 转义,如下
/^\d+\.\d+$/.test('1.23') // true
/^\d+.\d+$/.test('1@23') // false
复制代码
还有一个要注意的地方就是在两种创建正则的方式中使用转义的方式也不太一样,字面量就如上面所示,对象则要注意另一点,对象的方式创建传入的是字符串,如下
const reg = new RegExp('\d') //这里我们传入的是字符串'\d' 那他匹配的是什么?
reg.test(1) // false
reg.test('\d') // true
在字符串中 \ 代表的是转义
'\d' === 'd' // true d经过 \的转义还是d,所以我们需要这样写
const reg2 = new RegExp('\\d')
reg.test(1) // true
其实通过在控制台直接打印 reg我们也可以看到 得到的是/d/ 而不是/\d/
所以当在对象创建正则中使用\d、\w等需要多加一个\。
复制代码
看了这么多,试试?我要匹配字符串
<div>pig啦啦啦啦啦</div>
中span标签里面的内容
const str = `
dog?抓不到我<div>
pig?抓我
</div>啦啦啦啦
`
str.match(/<div>[\s\S]+<\/div>/)
复制代码
这里要注意中的 / 要转义,这里没有使用.+
来匹配标签中的内容是因为内容可能有换行符,而使用了[\s\S]
,\s
匹配换行符,\S
匹配除了换行符,加起来就是匹配所有字符,同理:[\d\D]
模式修正符
i、g、m
i
不区分大小写, /pig/i.test('PiG') // true
g
全局匹配, /pig/g.test('PiG') // true
'digdig'.replace(/d/,'p') //pigdig 只替换了一个p就结束了
'digdig'.replace(/d/g,'p') // pigpig
'Digdig'.replace(/d/ig,'p') // pigpig
复制代码
m
多行匹配, 可以理解成一个多行的字符串加了m
进行匹配,就变成每行单独对待。
其实主要就用i和g其余的用的真不多。
u
就是按照unicode(utf-8)进行匹配(有些宽子节匹配时可能出现乱码,可以加上u)
'pig'.match(/\p{L}/u) // 这里的意思就是匹配字符串的属性是否有L,需要配合u来使用
'p,i。g;'.match(/\p{P}/gu) //匹配表单符号 [",", "。", ";"]
关于这个还有很多建议查看官网
复制代码
y
粘连,提高效率,这里直接引用阮一峰的es6里面写的。
y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
const str = `1234pig,pig,22223332232131231231231231`
const reg = /pig/y
reg.lastIndex = 4 //让从4开始匹配
reg.exec(str)
reg.exec(str) // 因为要匹配的内容是连续的,后续的内容无需匹配
复制代码
? 禁止贪婪
正则时贪婪的,会尽可能的多匹配
'piggg'.match(/pig+/) // ["piggg"]
'piggg'.match(/pig+?/) // ["pig"]
'piggg'.match(/pig*?/) // ["pi"]
'piggg'.match(/pig{1,}?/) // ["pig"]
就是让他尽可能的少匹配
复制代码
<span>pig</span><span>pig</span>dog<span>pig</span>
这样一个字符串一个一个取出span标签和内容
const str = `<span>pig1</span><span>pig2</span>dog<span>pig3</span>`
str.match(/<span>.+<\/span>/g) // ["<span>pig1</span><span>pig2</span>dog<span>pig3</span>"]
因为正则时贪婪的所以它会尽可能的多匹配 就变成了开头的span 一直匹配到字符串结尾的span,所以我们要禁止贪婪
str.match(/<span>.+?<\/span>/g) // ["<span>pig1</span>", "<span>pig2</span>", "<span>pig3</span>"] 尽可能的少匹配
复制代码
断言
(?=xx)
先行断言,其实就是后边是什么
如下,匹配后面是pig的内容(断言只是做条件,所以不会出现在匹配的结果中)
(?<=xx)
后行断言,就是前面是什么
(?!xx)
零宽负向先行断言,就是后边不是什么
(?<!xx)
零宽负向后行断言,就是前面不是什么
写一下简单密码的正则,要求:字母、数字、下划线组成/^(?=.*\d)(?=.*[a-z])(?=.*_)[\da-z_]*$/
到这里就已经结束了,正则其实也很有意思的,可以去找一些正则的题来试试。
上面那题的答案:/^(a+)(a+)-\1=\2$/
看到这了不如来答个题?
字符串:haha (123 pig 456) 456 789 (cat 234) abcc (pig 123) a (dog)ll (95 monkey 27)
依次取出括号内没有pig的内容,要的结果["cat 234", "dog", "95 monkey 27"]
,欢迎评论区留言。