本文详细解析JavaScript中正则表达式的五大核心方法:match、search、replace、exec和test。重点阐述全局匹配标志g的作用、捕获分组在replace中的特殊语法(如$1、$&),以及RegExp.lastIndex属性在非全局匹配下导致的死循环陷阱与跨浏览器行为差异,帮助开发者避免常见错误。
JavaScript 正则表达式核心方法详解
string 对象
1、str.match(RegExp)
str.match(RegExp) 方法
在字符串str中查找与正则表达式RegExp匹配的内容,并将结果以数组形式返回。
若正则表达式未设置全局标志(/g),则仅执行一次匹配操作。
代码如下:
var result = ("abc112dwfwabcwef2abc3wfwabcasqf453abcqwf24j234h").match(/abc\d*/g);
//结果
["abc112", "abc", "abc3", "abc", "abc"] 当正则表达式未启用全局匹配模式(即无g标记)时,返回数组的第一个元素为完整匹配的字符串,后续元素包含正则中定义的捕获组内容。此外,该结果数组还包含两个额外属性:
input:原始用于检测的字符串。
index:匹配子串在原字符串中的起始位置索引。
(关于这两个属性的具体行为,可参考 RegExp.exec() 方法的说明)。
2、str.search(regExp)
str.search(regExp) 方法
返回与正则表达式RegExp匹配的第一个子串在原字符串中的位置索引;若未找到匹配项则返回-1。此方法忽略全局标记(g)的效果,因为无论是否设置g,它只执行一次匹配。
该方法同样忽略 regExp 对象的 lastIndex 属性,搜索始终从字符串起始位置开始。
3、str.replace(RegExp,replaceText)
str.replace(RegExp,replaceText) 方法
将字符串中符合RegExp匹配的部分替换为replaceText指定的内容。若RegExp未设置全局标志,仅替换第一次匹配;若设置了全局模式,则替换所有匹配项。
当RegExp中包含捕获分组时,replaceText参数中的$符号具有特殊含义:
$1、$2、...、$99 // 对应RegExp中第1至第99个子表达式所匹配的文本。
$& // 与整个RegExp相匹配的子串。
$` // 位于匹配子串左侧的文本。
$' // 位于匹配子串右侧的文本。
$$ // 字面量匹配$符号本身。
需注意,replaceText中$后跟随的数字必须对应RegExp中实际存在的捕获分组数量。若仅设置了2个捕获组,引用$3将失去特殊替换含义,被视为普通字符。
("123ab12c11d_4532").replace(/a(b\d*)c(\d*)d/,"$1@$2-")
//将得到:
"123b12@11-_4532"
4、str.replace(RegExp,function)
str.replace(RegExp,function) 方法
str.replace 方法的第二个参数也可以是一个函数,该函数的返回值将作为替换后的内容。
注意,若要实现全局匹配替换,RegExp仍必须包含全局标记g。
传递给替换函数的参数依次包括:
匹配的完整字符串,
正则中定义的捕获子串(按顺序多个),
匹配字符串在原字符串中的起始位置,
原始用于匹配的字符串。
请根据RegExp中捕获分组的数量来定义函数参数个数。若参数定义过少,可能导致“匹配字符串的开始位置”和“用于匹配的原字符串”无法通过参数直接获取。此时可在函数内部使用arguments对象解决,arguments[arguments.length-2]即为匹配字符串的开始位置,arguments[arguments.length-1]即为用于匹配的原字符串。
代码如下:
var newStr = ("123ab12c11d_4532").replace(/a(b\d*)c(\d*)d/g,function(s,s1,s2,pos,oldStr){
return "@"+s1+"@"+s2+"@";
}) ;
//将得到
"123@b12@11@_4532" 5、str.split(RegExp[,limit])
str.split(RegExp[,limit]) 方法
将字符串str按照符合RegExp匹配的子串进行分割,生成数组。limit参数可选,用于限制返回数组的最大长度。
("ada2afa4fcas6afa").split(/\d/,3) // 结果为 "ada,afa,fcas"
6、RegExp.exec("str") 方法
RegExp.exec("str") 方法
在字符串str中查找与RegExp匹配的内容。需注意,每次执行该方法仅匹配一次。若要匹配多个结果,需将RegExp设置为全局模式(/g),并多次调用exec()方法。每次匹配返回值为 result = RegExp.exec("str")。
result是一个数组,其长度通常为1(若包含捕获组则长度会增加),数组元素为找到的匹配子串。
此外,该数组对象被额外赋予了两个属性:
result.index 表示匹配子串在原字符串中的起始位置。
result.input 即为原始字符串。
当无法再找到符合匹配条件的子串时,返回 result = null,并将 RegExp.lastIndex 重置为0。
RegExp.lastIndex 是正则表达式对象的属性,指示当前匹配操作从字符串的哪个索引位置开始,初始值为0。
如果RegExp被设置为全局模式,在匹配完一个字符串后,使用同一个RegExp实例对新字符串进行匹配前,请先手动设置 RegExp.lastIndex=0。
如果RegExp未设置为全局匹配模式,而在程序中编写了循环,试图根据返回值result来决定是否终止匹配以遍历整个字符串,那么只要存在符合匹配条件的子串,就必定造成死循环。这是因为非全局匹配每次只匹配第一个子串,result永远不为空,导致循环无法退出。这是一个常见的编程错误。
代码如下:
var str = "1Visit W3School, W3School is a place to study web technology.";
var patt = new RegExp("W3School","g");
var result;
document.write(patt.lastIndex+"<br />");
document.write("=====================================<br />");
while ((result = patt.exec(str)) != null) {
document.write(patt.lastIndex+"<br />");
document.write(result.constructor.name+"<br />");
document.write(result.length+"<br />");
document.write(result[0]+"<br />");
document.write(result.index+"<br />");
document.write(result.input+"<br />");
document.write("=====================================<br />");
}
document.write(patt.lastIndex+"<br />");
// 运行结果:
=====================================
Array
W3School
Visit W3School, W3School is a place to study web technology.
=====================================
Array
W3School
Visit W3School, W3School is a place to study web technology.
===================================== 7、RegExp.test("str") 方法
RegExp.test("str") 方法
该方法与 RegExp.exec 类似,但仅返回布尔值true或false。
RegExp.lastIndex 的含义相同(这是RegExp对象的属性,与使用test还是exec方法无关)。
如果同一个RegExp实例先后调用了test方法和exec方法,可能需要手动设置 RegExp.lastIndex=0,因为这些方法共享同一个RegExp对象的lastIndex属性。
代码如下:
var str = "1Visit W3School, W3School is a place to study web technology.";
var patt = new RegExp("W3School","g");
var result ;
result = patt.test(str);
alert(result); //true
result = patt.test(str);
alert(result); //true
result = patt.test(str);
alert(result); //false lastIndex 属性与浏览器差异
在IE9+、较新版本的Chrome、Firefox浏览器中,str.match(reg)执行完毕后,无论是否全局匹配或是否存在匹配结果,lastIndex都会被重置为0;reg.test(str)执行后,若正则非全局匹配,lastIndex也会被重置为0。而在IE8及以下版本中,正则匹配执行后,除非没有匹配结果,否则re.lastIndex会更新为最后一个匹配字符串结尾字符的位置+1,即lastIndex未被重置。