我正在开发一个基于JavaScript的项目,该项目涉及一个基本的Bash启发的脚本系统,我正在使用正则表达式将行分成(许多类型的)令牌。
一个这样的令牌类当然是递归$()
构造。该构造可以任意嵌套。我正在尝试设计一个JavaScript正则表达式来匹配这种类型的令牌,而不会意外地将部件留在后面或抓住其他令牌的部分。
给出一个如下例子的字符串:
“$(foo $(bar)fizz $(buzz))$($(其他))”
它由单个标记组成,每个标记由外部$()分隔,后跟空格或字符串结尾,
匹配字符串中的第一个这样的标记,包括其打开的$(包括其最终结束)
如果字符串中出现 where 的不平衡构造,则此正则表达式的行为被视为未定义且无关紧要。
所以在上面的示例中,正则表达式应匹配“$(foo $(bar)fizz $(buzz))”
输入字符串和返回的匹配都通过String.prototype.trim()
传递,因此前导和尾随空格无关紧要
我能够认为不平衡的构造是一个未定义的情况,因为一旦提取就消耗这种类型的令牌的代码会进行自己的余额检查。即使正则表达式返回一个由外部$()包围的匹配项,该错误最终也会在其他地方被捕获。
有一段时间我一直在使用这个正则表达式:
/\$\(.*?\)(?!(?:(?!\$\().)*\))(?:\s+|$)/
这似乎工作了很长一段时间。它匹配任意嵌套的平衡结构,只要它们在同一级别没有多个嵌套。这种情况在最初测试时以某种方式滑过了我的脑海。它以懒惰的重复消耗令牌的内容,并断言在关闭paren之后没有另一个关闭的paren,然后才打开$(。这当然是由上面例子中的令牌打破的。
我知道传统的“平衡构造正则表达式问题”在没有子程序/递归的情况下是不可解决的。但是我希望,因为我只需要匹配平衡的结构而不是不匹配不平衡的结构,所以有一些聪明的方法来欺骗。
答案 0 :(得分:2)
因此,在上面的例子中,正则表达式应匹配
$(foo $(bar) fizz $(buzz))
我认为它的解决方案与I posted today(基于Matching Nested Constructs in JavaScript, Part 2 Steven Levithan)几乎相同,但您需要的是添加分隔符,因为它们是已知的。
使用示例:
matchRecursiveRegExp("$(foo $(bar) fizz $(buzz)) $(something $(else))", "\\$\\(", "\\)");
代码:
function matchRecursiveRegExp (str, left, right, flags) {
var f = flags || "",
g = f.indexOf("g") > -1,
x = new RegExp(left + "|" + right, "g" + f),
l = new RegExp(left, f.replace(/g/g, "")),
a = [],
t, s, m;
do {
t = 0;
while (m = x.exec(str)) {
if (l.test(m[0])) {
if (!t++) s = x.lastIndex;
} else if (t) {
if (!--t) {
a.push(str.slice(s, m.index));
if (!g) return a;
}
}
}
} while (t && (x.lastIndex = s));
return a;
}
document.write("$(" + matchRecursiveRegExp("$(foo $(bar) fizz $(buzz)) $(something $(else))", "\\$\\(", "\\)") + ")");

请注意,此解决方案不支持全局匹配。