JavaScript正则表达式匹配平衡的结构,而不关心不平衡的结构

时间:2015-08-13 19:11:40

标签: javascript regex

我正在开发一个基于JavaScript的项目,该项目涉及一个基本的Bash启发的脚本系统,我正在使用正则表达式将行分成(许多类型的)令牌。

一个这样的令牌类当然是递归$()构造。该构造可以任意嵌套。我正在尝试设计一个JavaScript正则表达式来匹配这种类型的令牌,而不会意外地将部件留在后面或抓住其他令牌的部分。

问题,更具体地说:

给出一个如下例子的字符串:
“$(foo $(bar)fizz $(buzz))$($(其他))”
它由单个标记组成,每个标记由外部$()分隔,后跟空格或字符串结尾, 匹配字符串中的第一个这样的标记,包括其打开的$(包括其最终结束) 如果字符串中出现 where 的不平衡构造,则此正则表达式的行为被视为未定义且无关紧要。

所以在上面的示例中,正则表达式应匹配“$(foo $(bar)fizz $(buzz))”

进一步的使用细节:

输入字符串和返回的匹配都通过String.prototype.trim()传递,因此前导和尾随空格无关紧要

我能够认为不平衡的构造是一个未定义的情况,因为一旦提取就消耗这种类型的令牌的代码会进行自己的余额检查。即使正则表达式返回一个由外部$()包围的匹配项,该错误最终也会在其他地方被捕获。

到目前为止我尝试了什么

有一段时间我一直在使用这个正则表达式:
/\$\(.*?\)(?!(?:(?!\$\().)*\))(?:\s+|$)/
这似乎工作了很长一段时间。它匹配任意嵌套的平衡结构,只要它们在同一级别没有多个嵌套。这种情况在最初测试时以某种方式滑过了我的脑海。它以懒惰的重复消耗令牌的内容,并断言在关闭paren之后没有另一个关闭的paren,然后才打开$(。这当然是由上面例子中的令牌打破的。

我知道传统的“平衡构造正则表达式问题”在没有子程序/递归的情况下是不可解决的。但是我希望,因为我只需要匹配平衡的结构而不是不匹配不平衡的结构,所以有一些聪明的方法来欺骗。

1 个答案:

答案 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))", "\\$\\(", "\\)") + ")");




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