正则表达式里问号?的用法
文章原文:https://www.cnblogs.com/yalong/p/15183458.html
1.普通的问号符号
因为 ?
是特殊符号,所以如果想把 ?
当做正常的问号匹配,就需要加转义 \?
示例
var regex = /123\?456/
var str = '123?456'
regex.test(str) // true
2.量词
问号可以表示重复前面内容的0次或一次,也就是要么不出现,要么出现一次
示例
var regex = /1?23/
regex.test('123') // true
regex.test('1123') // true
regex.test('1234') // true
regex.test('121') // false
3.惰性模式匹配
量词模式是贪婪模式,在量词后面加上问号,就变成了惰性匹配
看如下量词的表格
模式 | 说明 |
---|---|
连续出现 n 到 m 次。贪婪模式 | |
至少连续出现 n 次。贪婪模式 | |
连续出现 n 次。贪婪模式 | |
? | 等价于 {0,1}。贪婪模式 |
+ | 等价于 {1,}。贪婪模式 |
* | 等价于 {0,}。贪婪模式 |
量词后面加上问号后如下 | |
模式 | 说明 |
---- | ---- |
{n,m}? | 连续出现 n 到 m 次。惰性模式 |
{n,}? | 至少连续出现 n 次。惰性模式 |
{n}? | 连续出现 n 次。惰性模式 |
?? | 等价于 {0,1}?。惰性模式 |
+? | 等价于 {1,}?。惰性模式 |
*? | 等价于 {0,}?。惰性模式 |
贪婪模式 跟 惰性模式的区别
- 贪婪匹配是先看整个字符串是否匹配,如果不匹配,它会去掉字符串的最后一个字符,并再次尝试,如果还不匹配,那么再去掉当前最后一个,直到发现匹配或不剩任何字符。
- 惰性匹配是从左侧第一个字符开始向右匹配, 先看第一个字符是不是一个匹配, 如果不匹配就加入下一个字符再尝式匹配, 直到发现匹配
4.非捕获性分组
- 正常只使用括号就是捕获模式,可以捕获括号里的数据,保存在内存中,所以捕获模式会占用更多内存
- 非捕获模式,就是在里面的最前面加
?:
示例
RegExp 会保存分组里的数据, 如下所示
var regex = /(\d{4})-(\d{2})-(\d{2})/
regex.test('2011-11-12') // true
RegExp.$1 // "2011"
RegExp.$2 // "11"
RegExp.$3 // "12"
使用?:
的分组就是非捕获模式,RegExp 不会保存该分组的数据,如下所示
var regex = /(?:\d{4})-(\d{2})-(?:\d{2})/
regex.test('2011-11-12') // true
RegExp.$1 // "11"
RegExp.$2 // ""
5.断言
1.正先行断言(前瞻)
(?=X)
2.负先行断言(前瞻)
(?!X)
3.正后发断言(后顾)
(?<=X)
4.负后发断言(后顾)
(?<!X)
语法 | 说明 |
---|---|
(?=X ) | 正先行断言。仅当子表达式 X 在 此位置的右侧匹配时才继续匹配。例如,/w+(?=/d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯 |
(?!X) | 负先行断言。仅当子表达式 X 不在 此位置的右侧匹配时才继续匹配。例如,例如,/w+(?!/d) 与后不跟数字的单词匹配,而不与该数字匹配 |
(?<=X) | 正后发断言。仅当子表达式 X 在 此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯 |
(?<!X) | 负后发断言。仅当子表达式 X 不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99 的实例匹配 |
简单来说,前瞻就是 看后面等于(?=), 后面不等于 (?!), 后顾就是 前面等于 (?<=), 前面不等于 (?<!)
比如 (?<!AA)eat(?=milk) 表示, eat 前面不能是AA, 后面必须是 milk
比如 (?<=AA)eat(?!milk) 表示 eat 前面必须是AA, 后面不能是milk
示例
let str1 = "VVeatmilk"
let str2 = "AAeatfood"
let patt1 = new RegExp("(?<!AA)eat(?=milk)");
let patt2 = new RegExp("(?<=AA)eat(?!milk)");
let result1 = patt1.test(str1);
let result2 = patt2.test(str2);
console.log(result1) // true
console.log(result2) // true
以(?=p) 和 (?!p)为例
(?=p)
,其中 p 是一个子模式,即 p 前面的位置,或者说,该位置后面的字符要匹配 p
比如 (?=l)
,表示 l
字符前面的位置,例如:
var result = "hello".replace(/(?=l)/g, '#');
console.log(result);
// => "he#l#lo"
而 (?!p) 就是 (?=p) 的反面意思,比如:
var result = "hello".replace(/(?!l)/g, '#');
console.log(result);
// => "#h#ell#o#"
(?<=p)
和 (?<!p)
同理