本文详细解析JavaScript正则表达式中问号(?)的四种核心用法。包括通过+?, *?, {n,m}?实现非贪婪匹配;利用(?:...)创建无编号的无捕获分组;使用(?=)和(?!)进行正向与负向零宽断言;以及表示重复0次或1次的可选匹配。结合具体代码示例,帮助开发者准确掌握不同场景下的正则编写技巧。
非贪婪匹配:限制重复次数
在表示重复次数的元字符(如+、*、{n,m})后添加问号,可将默认的贪婪匹配模式转换为非贪婪(最小)匹配。例如,{2,3}?会尽可能少地匹配重复次数,而非尽可能多。
var pattern=/\w{2,3}/;
console.log("aaaa".match(pattern)[0]);
/*结果"aaa";贪婪模式下会尽可能多的匹配,
所以会匹配3个重复的字符
*/
var pattern2=/\w{2,3}?/;
console.log("aaaa".match(pattern2)[0]);
/*
*结果"aa";加问号后会尽可能少的匹配重复次数,
*所以匹配到了2个重复的字符
*/
无捕获分组:(?:...)的用法
在分组括号内使用?:前缀,如(?:...),可以创建一个没有编号的无捕获分组。这种分组参与整体匹配,但不会在反向引用(如$1)中产生独立的捕获编号,常用于简化复杂正则的结构。
var pattern=/(ab)\w+(ba)/;
console.log("abcba_".replace(pattern,"$1"));
/*结果"ab_";匹配到的字符被第一个分组(ab)
*替换
*/
var pattern2=/(?:ab)\w+(ba)/;
console.log("abcba_".replace(pattern2,"$1"));
/*
*结果"ba_";第一次分组内加入了?:,产生的是一个
*没有编号的分组,所以$1匹配的字符是第二个分组,
*也就是第一个编号分组(ba)相匹配的文本内容
*/
零宽断言:(?=)与(?!)
零宽正向断言(?=)和负向断言(?!用于指定某个位置前后的字符条件。正向断言(?=exp)要求该位置右侧必须匹配exp;负向断言(?!exp)要求该位置右侧不能匹配exp。它们不消耗字符,仅作为位置判断。
var pattern=/str(?=ings)ing/;
console.log("strings.a".match(pattern));
console.log("strings.a".match(/string(?=s)/));
console.log("string_x".match(pattern));
console.log("string_x".match(/string(?=s)/));
/*前两个结果是["string"],后两个结果是null;
*str(?=ings)ing/匹配"string",r后面的位置右边必须跟
*上ings;和/string(?=s)/一样;匹配"string";g后面的位置
*的右边必须跟一个s。"string_x"虽然也含有"string"但是
*不满足(?=...)括号内的条件
*/
var pattern=/string(?!s)/;
console.log("strings".match(pattern));//null
console.log("string.".match(pattern));//["string"]
/*(?!...)某位置右边不能有!后匹配的字符,
*string(?!s)/匹配"string","g"后不能跟"s"
*/
可选匹配:0次或1次
在表示重复次数的元字符后单独使用问号,表示该元素是可选的,即允许匹配0次或1次。这通常用于处理可选后缀或可选参数的情形。