深⼊学习正则表达式
正则⾥括号的⽤法
1. 分组
分组:正则表达式⾥括号的表达式为另外⼀组匹配规则
捕获括号:被匹配的⼦字符串可以在结果数组的元素 [1]-[n] 中找到,或在被定义的 RegExp 对象的属性 $1-$9 中找到。
代码举例:
let reg = /\d+(\D+)/
<('123456abcd')
suck什么意思// ["123456abcd", "abcd", index: 0, input: "123456abcd", groups: undefined]
console.log(RegExp.$1)
// "abcd"
复制代码
在这个正则表达式⾥我们括号期望的是⼀组⾮数字的匹配项,并且执⾏匹配后可在执⾏结果的[1]或者RegExp.$1得到匹配值。正则表达式括号的分组在实际开发中对于我们解决问题有⾮常⼤的⽤处,例如place()这个⽅法
代码举例:
let str = '123abc'
let reg = /(\d+)(\D+)/
let newStr = place(reg, '$2$1')
console.log(newStr) // abc123
console.log(word,$1,$2)
// word代表字符串在正则匹配到的值, $1代表第⼀个括号的匹配项, $2代表第⼆个括号的匹配项
// 123abc, 123, abc
})
复制代码
使⽤正则表达式应⽤于字符串处理,在上⾯的例⼦⾥我们很容易得就把数字和字母的匹配项互换位置。
belong是什么意思在另外⼀种情况下如果不想要捕获这个匹配项,但是⼜需要加括号匹配条件,我们可以使⽤⾮捕获括号
⾮捕获括号:匹配项不能够从结果数组的元素 [1]-[n] 或已被定义的 RegExp 对象的属性 $1-$9 再次访问到。
代码举例:
let reg = /\d+(?:\D+)/
<('123456abcd')
/
/ ["123456abcd", index: 0, input: "123456abcd", groups: undefined]
复制代码
preview日语 你好在例⼦⾥执⾏匹配后括号⾥的匹配项不会再出现结果⾥。
2.反向引⽤
反向引⽤:⼀个反向引⽤(back reference),指向正则表达式中第 n 个括号(从左开始数)中匹配的⼦字符串。
代码举例:
reg = /(\d+)\D+\1/
<('123abc123')
南京蛋糕培训学校
// ["123abc123", "123", index: 0, input: "123abc123", groups: undefined]
复制代码
在正则表达式⾥\1代表的是\d+,当我们在表达式⾥有需要重复的时候可以⽤这种写法。
3.零宽断⾔
零宽断⾔:指⼀个⽤来描述或者匹配⼀系列符合某个句法规则的字符串的单个字符串。
1. (?=pattern) 正向先⾏断⾔:代表字符串中的⼀个位置,紧接该位置之后的字符序列能够匹配pattern。
2. (?!pattern) 负向先⾏断⾔:代表字符串中的⼀个位置,紧接该位置之后的字符序列不能匹配pattern。
3. (?<=pattern) 正向后⾏断⾔:代表字符串中的⼀个位置,紧接该位置之前的字符序列能够匹配pattern。
4. (?<!pattern) 负向后⾏断⾔:代表字符串中的⼀个位置,紧接该位置之前的字符序列不能匹配pattern。
正则表达式的括号有时候⽤来表达断⾔,具体的细节我们在下⾯问内容详细说。
贪婪模式与⾮贪婪模式
贪婪模式与⾮贪婪模式也是正则⾥⾯⽐较常见的问题了,平时也会经常应⽤于开发中解决问题。理解贪婪模式和⾮贪婪模式对我们理解正则引擎执⾏匹配⾮常有帮助。
瘦脸化妆技巧
贪婪模式
贪婪模式会匹配尽可能多的字符,贪婪模式⽤于匹配优先量词修饰的⼦表达式,匹配优先量词包括:“{m,n}”、“{m,}”、“?”、“*”和“+”
代码举例:
let reg = /\d*/
<('1234567890')
["1234567890", index: 0, input: "1234567890", groups: undefined]
复制代码
*号代表匹配任意次数,⽤⼤括号代表即{0,},在贪婪模式下尽可能多的匹配,在例⼦中因为整个字符串完全匹配,所以匹配值为1234567890。
⾮贪婪模式
⾮贪婪模式会匹配尽可能少的字符,在匹配量词后⾯加上问号就可触发⾮贪婪模式:“{m,n}?”、“{m,}?”、“??”、
“*?”和“+?”
代码举例:
let reg = /\d*?/
欠款英文('1234567890')
// ["", index: 0, input: "1234567890", groups: undefined]
复制代码
*号代表匹配任意次数,⽤⼤括号代表即{0,},因为*号可代表匹配0次,在⾮贪婪模式下尽可能少的匹配,所以在这个例⼦⾥匹配项为空,即不匹配任何字符串。
零宽断⾔
正则表达式的断⾔功能⾮常强⼤,学习正则的断⾔应⽤,对于解决我们开发中的问题提供了新的思路。
在理解断⾔的执⾏过程可能会稍微有点绕,但是作为⼀个开发肯定要有⼀颗爱折腾的⼼,哈哈。
下⾯将只使⽤正向先⾏断⾔来说明断⾔的执⾏,其他的三个模式也是⼤同⼩异。
先看⼀个简单例⼦:
let reg = /abc(?=123)/
<('abc123')
// ["abc", index: 0, input: "abc123", groups: undefined]
let reg2 = /abc(?=1234)/
<('abc123')
// null
let reg3 = /abc(?=12)/
<('abc123')
// ["abc", index: 0, input: "abc123", groups: undefined]
复制代码
先按照正则的字⾯意思理解,/abc(?=123)/期望的匹配为即匹配abc,且abc后⾯的字符串能够满⾜括号的匹配规则,注意的是括号⾥⾯可以为其他正则表达式,并不是说abc后⾯只能包含123,⽽是后⾯可以满⾜括号的匹配则为断⾔成功。
在reg2的匹配过程中,因为abc后⾯的字符串不满⾜括号的匹配规则,所以断⾔失败,执⾏匹配也失败了。
在这⼏个例⼦⾥还没有体现出我们概念⾥说的意思,重温⼀下正向先⾏断⾔的概念
(?=pattern) 正向先⾏断⾔:代表字符串中的⼀个位置,紧接该位置之后的字符序列能够匹配pattern
概念⾥说的意思断⾔是在字符串中寻找符合断⾔的⼀个位置
举例说明:
shepherdlet reg = /(?=abc).*/
<('123abc123')
// ["abc123", index: 3, input: "123abc123", groups: undefined]
复制代码
先分析正则表达式,在满⾜abc匹配条件的位置后⾯匹配任意字符。在这个例⼦⾥,存在abc满⾜断⾔的匹配规则,但是为什么匹配到的是abc123?
在这⾥就回到我们的标题,零宽断⾔,零宽的意思就是执⾏断⾔是不会消耗我们正则表达式在匹配过程中的字符串,并且,断⾔是在帮我们确定符合断⾔匹配规则的位置。所以,(?=abc)会帮我们确定⼀个断⾔成功的位置,即3和a之间的位置,然后在这个断⾔成功的位置开始执⾏匹配(.*)。
let reg = /(?=abc)\d+/
chinacouple自拍video<('123abc123')
// null
复制代码
在上⾯的例⼦中,虽然abc的断⾔成功,但是断⾔只是帮我们确定⼀个位置,然后再执⾏\d+匹配规则,因为断⾔是不会消耗字符串,所以实际上以abc123去和\d+匹配,最后匹配结果为null。
基于此我们可以使⽤断⾔帮我们从⼀开始检索整个字符串是否满⾜某些规则,有助于提升匹配效率。
如下例⼦,我们可以使⽤断⾔从⼀开始判断整个字符串是否全部由数字组成,如果断⾔失败,则不执⾏匹配,这对于我们应⽤于表单校验⾮常有助于提升效率。
reg = /(?=^\d+$)\d+/
<('123456') // 123456
<('123456a') // null
复制代码
shuku另外没有介绍到的三种模式也是⼤同⼩异,在这⾥也就不重复赘述。但是两种后⾏断⾔可能会存在兼容性问题,后⾏断⾔应该是ES2018新增的规范。
零宽断⾔的重点是要理解“零宽”以及“位置”这两个点。
最后总结⼀下:正则表达式是⼀门⾮常实⽤的⼯具语⾔,基本上只要学习了就能够对于我们实际开发中产⽣帮助,平时某些开发⼯具中也可以使⽤正则表达式去检索某些⽂档,对于提升效率真的是帮助⾮常⼤。