前两天写那个异步函数顺序执行的过程中,动态修改函数,遇到setTimeout,我需要提取执行的时间,形如:
setTimeout(function() {
output.innerText += '第三个异步函数,延迟1秒执行\n';
}, 1000);
要截取1000
这个值。经过分析,我发现setTimeout()这个函数闭合的圆括号)
与前一个逗号,
之间的内容,就是要截取的值。
代码
想了想,要确定闭合括号)
的位置,需要和开始位置(setTimeout
之后)的括号(
匹配。看了些文档后,写了下面的方法:
function match(str, startStr, item) {
var counter = 0,
end = -1,
matchLeft = item.charAt(0),
matchRight = item.charAt(1),
start = str.indexOf(startStr) + startStr.length;
search(start + 1);
function search(position) {
end = str.indexOf(matchRight, position);
if (end != -1) {
counter++;
var subStr = str.substring(start + 1, end).match(eval("/\\" + matchLeft + "/g"));
if (subStr !== null) {
var numsOfMatchLeft = subStr.length;
} else if (subStr === null) {
return;
}
if (counter > numsOfMatchLeft) {
return;
} else {
arguments.callee(end + 1);
}
} else {
console.warn('输入的配对符号有误');
}
}
return [start, end];
}
参数
match函数接收3个参数,str
是要匹配的文本,startStr
是需匹配字符,在文本中的具体位置,为了保证唯一性,一般要带入字符左侧若干文本,item
是要匹配的符号,按左右顺序写全两个,如'()','{}'
等。匹配最上面的setTimeout那个例子,可以这样调用。
var text = 'setTimeout(function() {\
output.innerText += \'第三个异步函数,延迟1秒执行\n\';\
}, 1000);'
match(text,'setTimeout(','()');
//返回符号的开始,结束位置数组
//[11, 71]
实现思路
左右匹配,只要把中间所有的匹配项找到即可。
以 ()
为例,首先从欲匹配符号(
位置的右侧开始寻找)
,设定一个累加计数器,用来记录)
的数量,如果找到,记下)
的位置,计数器自增。
并且在(
的位置与)
的位置间,查找(
的数量,与计数器进行比较。如果计数器的值小于(
的数量,说明该)
不是最终的与最开头的(
相匹配的括号。如果计数器的值等于(
的数量,说明所有()
已经一一对应,下一个)
就是最终的匹配括号。
重复上面的步骤,最终得到括号的位置。
这种方法不局限于括号,理论上可义匹配不相同的任意两项,也不局限于长度为1的字符,对位置稍加修改即可。