JavaScript RegExp exec() 方法详解:lastIndex、修饰符 i/g/m 原理与断点分析
本文深入解析 JavaScript 中 RegExp 对象的 exec() 方法。详细阐述两种正则声明方式,重点剖析 exec() 返回结果结构及核心的 lastIndex 属性机制。通过断点调试示例,逐一讲解忽略大小写(i)、全局匹配(g)及多行模式(m)修饰符的工作原理与行为差异,帮助开发者准确掌握正则匹配逻辑。
一、RegExp对象的声明及exec()方法的使用
在 JavaScript 中,创建 RegExp 对象主要有两种途径:
1)使用构造函数:var re=new RegExp(pattern,modifiers);
2)使用字面量语法:var re =/pattern/modifiers;
其中,pattern(模式)定义了匹配的规则表达式;modifiers(修饰符)用于控制匹配行为,包括全局匹配(g)、忽略大小写(i)和多行匹配(m)。这些修饰符可以单独使用,也可以自由组合,甚至可以不添加任何修饰符。
| 修饰符 | 释义 |
|---|---|
| i | 代表忽略大小写 |
| g | 代表全局匹配 |
| m | 执行多行匹配 |
示例:
1)使用构造函数创建:var re=new RegExp(pattern,modifiers);
var re1=new RegExp("\w{2}");
var re2=new RegExp("\w{2}","i"); 2)使用字面量创建:var re =/pattern/modifiers;
var re3=/\w{2}/;
var re4=/\w{2}/ig;使用RegExp对象的exec()方法:
直接调用该方法即可。若成功匹配到字符串,则返回一个包含匹配信息的数组;若未匹配到,则返回 null。
1) var re1=new RegExp("\w{2}");
var res1=re1.exec("要检索的字符串");2)var re3=/\w{2}/;
var res2=re3.exec("要检索的字符串");示例:
<!DOCTYPE html>
<html>
<head>
<title>exec()方法的使用</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
var re1=/\d[a-zA-Z]/; //匹配两位一个数字和一个忽略大小写的字母
var res1=re1.exec('aa2edj3djie7788');
var res2=re1.exec('458949468974484');
</script>
</body>
</html>通过断点调试观察 var res1=re1.exec('aa2edj3djie7788') 的执行结果。

继续通过断点观察 var res2=re1.exec('458949468974484') 的执行结果。

综上所述,exec() 方法的返回结果主要有两种情况:一是包含匹配字符串及相关信息的数组,二是表示未匹配的 null。
二、RegExp对象和执行exec()得到的结果分析
1)首先关注RegExp对象本身。
在 RegExp 对象中,我们主要关注 lastIndex 属性。该属性的值表示下一次检索字符串时开始匹配的起始索引。结合上述代码和断点进行说明。
<!DOCTYPE html>
<html>
<head>
<title>exec()方法的使用</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
var re1=/\d[a-zA-Z]/; //匹配两位一个数字和一个忽略大小写的字母
var res1=re1.exec('aa2edj3djie7788');
</script>
</body>
</html>观察调用 exec() 方法前的 RegExp 对象状态。

观察调用 exec() 方法后的 RegExp 对象状态。

注意,在调用 exec() 方法前后,lastIndex 的值可能未发生变化,但该属性至关重要: 1)lastIndex 决定了每次匹配时检索字符串的起始索引位置。 2)当使用了 g 修饰符后,此属性是动态变化的,这对于理解 g 修饰符的行为非常关键。
2)执行exec()得到的结果分析。
这里我们仅断点查看数组结果,因为 null 结果较为直观。
下面看断点截图。

查看数组对象各个属性的含义: var a=res1[0]; // 匹配到的字符串 var index=res1.index; // 匹配到的字符串的第一个字符 在被检索字符串String中的位置 var input=res1.input; // 被检索的字符串 var length=res1.length; // 数组的长度
三、修饰符 i 的使用
修饰符 i 表示在匹配时忽略大小写,下面通过代码进行演示。
<!DOCTYPE html>
<html>
<head>
<title>exec()方法的使用</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
var re1=new RegExp("\d[a-z]"); //匹配两位一个数字和一个忽略大小写的字母
var re2=new RegExp("\d[a-z]","i");
var res1=re1.exec('8AJDJDJ');
var res2=re2.exec('8AJDJDJ');
</script>
</body>
</html>断点查看 var res1=re1.exec('8AJDJDJ') 的执行结果。

断点查看 var res2=re2.exec('8AJDJDJ') 的执行结果。

四、修饰符 g 的使用
修饰符 g 代表全局匹配,即对整个要检索的字符串进行完整匹配。
其原理是:当使用了 g 修饰符,每次调用 exec() 方法并匹配到字符串后,lastIndex 属性的值会随之改变。而未使用 g 修饰符时,每次调用 exec() 后,lastIndex 值始终为 0,因此每次调用 exec() 最多只会检索出第一个相同的匹配结果。
当使用了 g 修饰符,找到匹配的字符串后,lastIndex 的值会被重置为匹配内容下一个字符在需要检索字符串中的位置索引。
下面通过代码和断点逐步解析 g 的原理。
<!DOCTYPE html>
<html>
<head>
<title>exec()方法的使用</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
// 使用 g 修饰符 全局搜索
var test1=new RegExp("\d\w","g");
var res1=test1.exec("1a2b3c4d5e");
var res2=test1.exec("1a2b3c4d5e");
//综上可知, 使用g全局搜索的时候,我们可以使用循环
do{
var res=test1.exec("1a2b3c4d5e");
if(res!=null){
console.log(res[0]);
}
}while(res!=null);
//没有使用 g
var test2=/\d{2}/;
var result=test2.exec("22dhdhj33djdj44");
var result1=test2.exec("22dhdhj33djdj44");
</script>
</body>
</html>断点查看 var test1=new RegExp("\d\w","g");

断点查看执行一次后 RegExp 对象 var res1=test1.exec("1a2b3c4d5e");

再次执行一次,查看断点 var res2=test1.exec("1a2b3c4d5e");

综上可知,在使用 g 全局搜索时,可以根据 lastIndex 对整个要检索字符串进行匹配。因此,我们可以使用循环来获取要检索字符串中所有匹配的结果。
do{
var res=test1.exec("1a2b3c4d5e");
if(res!=null){
console.log(res[0]);
}
}while(res!=null);查看结果,由于我们已经执行了两次,此时 lastIndex 为 4,因此循环检索匹配从要检索字符串的索引 4 开始。

接下来重点查看执行到结果为 res[0]= 5e 时的断点。

查看此时的 RegExp 对象。
此时可以看到 lastIndex 值为 10,即下次匹配从索引 10 开始。已知要检索的字符串“1a2b3c4d5e”的长度为 10,因此下一次调用结果为 null。

查看下一步,当结果为 null 时的断点截图。

我们注意到,此时 RegExp 对象的属性 lastIndex 的值被重置为 0。即下一次再调用 exec() 方法,会从要检索字符串的 0 索引位置开始匹配。
通过上述一步步断点,相信你已经明白了全局搜索 g 修饰符的使用原理。接下来再看没有设置 g 时的代码断点。
查看这一步,var test2=/\d{2}/; 断点。刚开始 test2 的 lastIndex 值为 0。

执行一次,var result=test2.exec("22dhdhj33djdj44"); 得到的结果为 22。

重点查看此时的 test2 属性 lastIndex 的值,发现 lastIndex 值仍为 0。

因为当非全局搜索时,test2 不管调用几次 exec() 方法,其属性 lastIndex 值都为 0。所以,非全局搜索时,每次调用 exec() 方法总是得到第一个相同的结果。
五、修饰符 m 的使用
修饰符 m 执行多行匹配,代表多行模式(multiline)。
使用 m 时需要注意:1)当要检索的字符串为单行时,使用 m 无意义。很明显,只有一行字符串时使用 m 没有作用。2)当要检索的字符串包含换行符 \n 或 \r\n 时,这里要看正则表达式是否包含位置符号 ^ 和 $:
①当正则表达式中存在 ^和$符号时,使用了 m ,则:
“^”与字符串开始位置以及“\n”或“\r”之后的位置相匹配,“$”与字符串结束位置以及“\n”或“\r”之前的位置相匹配。
②当正则表达式中存在 ^和$符号时,没有使用了 m ,则:
“^”与字符串的开始位置相匹配,“$”与字符串的结束位置相匹配。
③当正则表达式中不存在 ^和$符号时,使用了 m ,则:
正则表达式正常匹配字符串。
④当正则表达式中不存在 ^和$符号时,没有使用了 m ,则:
正则表达式正常匹配字符串。
下面具体看第二条注意中各种可能情况。
<!DOCTYPE html>
<html>
<head>
<title>exec()方法的使用</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
var re=/^ad{2}$/m;
var res=re.exec("adfdd1727\r\naddjdsljs\r\nadd\nshshsh");
var re1=/^ad{2}$/;
var res1=re1.exec("adfdd1727\r\naddjdsljs\r\nadd\nshshsh");
</script>
</body>
</html>断点查看结果:
1)var res=re.exec("adfdd1727\r\naddjdsljs\r\nadd\nshshsh");

这是情况①当正则表达式中存在 ^和$符号时,使用了 m ,则:
“^”与字符串开始位置以及“\n”或“\r”之后的位置相匹配,
“$”与字符串结束位置以及“\n”或“\r”之前的位置相匹配。
2)var res1=re1.exec("adfdd1727\r\naddjdsljs\r\nadd\nshshsh");

这是情况②当正则表达式中存在 ^和$符号时,没有使用了 m ,则:
“^”与字符串的开始位置相匹配,
“$”与字符串的结束位置相匹配。
<!DOCTYPE html>
<html>
<head>
<title>exec()方法的使用</title>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
var str="fdd1727\r\naddjdsljs\r\nadd\nshshsh";
var re=/ad{2}/m;
var res=re.exec(str);
var re1=/ad{2}/;
var res1=re1.exec(str);
</script>
</body>
</html>断点查看结果:
1)var res=re.exec(str);

这是情况③
当正则表达式中不存在 ^和$符号时,使用了 m ,则:
正则表达式正常匹配整个要检索的字符串。
2)var res1=re1.exec(str);

这是情况④
当正则表达式中不存在 ^和$符号时,没有使用了 m ,则:
正则表达式正常匹配整个要检索的字符串。
综上所知: 使用 m 的时候,只有当 要检索的字符串中有换行符,且正则表达式中有 ^和$位置符号时,m 才会起作用; 其他情况下使用和不使用 m 都当作正常的字符串匹配检索。
以上就是JavaScript中exec()方法详解的详细内容,更多关于JavaScript exec()方法的资料请关注本站其它相关文章!
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
