0

这是我到目前为止创建的正则表达式: \((.+?)\)

这是我的测试字符串:(2+2) + (2+3*(2+3))

我得到的比赛是:

(2+2)(2+3*(2+3)

我希望我的比赛是:

(2+2)(2+3*(2+3))

我应该如何修改我的正则表达式?

4

2 回答 2

4

您不能使用正则表达式解析父级表达式。有一个数学证明正则表达式不能做到这一点。带括号的表达式是一种上下文无关的语法,因此可以被下推自动机(堆栈机器)识别。

无论如何,您可以定义一个正则表达式,该表达式将适用于任何小于 N 括号的表达式,具有任意有限 N(即使表达式会变得复杂)。你只需要承认你的括号可能包含另一个任意数量的 parenteses。

\(([^()]+(\([^)]+\)[^)]*)*)\)

它是这样工作的:

  1. \(([^()]+匹配一个左括号,后跟不是括号的;
  2. (\([^)]+\)[^)]*)*可选地,可能有另一个组,由一个左括号组成,其中包含一些内容,然后是一个匹配的右括号。后面可能会出现一些其他非括号字符。这可以重复任意次数。无论如何,最后,必须有
  3. )\)另一个右括号,与第一个匹配。

这应该适用于嵌套深度 2。如果您想要嵌套深度 3,则必须进一步递归,允许我在第 (2) 点描述的每个组都有一个嵌套的括号组。

如果您使用堆栈,事情会变得容易得多。如:

foundMatches = [];
mStack = [];
start = RegExp("\\(");
mid = RegExp("[^()]*[()]?");
idx = 0;
while ((idx = input.search(start.substr(idx))) != -1) {
    mStack.push(idx);
    //Start a search
    nidx = input.substr(idx + 1).search(mid);
    while (nidx != -1 && idx + nidx < input.length) {
        idx += nidx;
        match = input.substr(idx).match(mid);
        match = match[0].substr(-1);
        if (match == "(") {
            mStack.push(idx);
        } else if (mStack.length == 1) {
            break;
        }
        nidx = input.substr(idx + 1).search(mid);
    }
    //Check the result
    if (nidx != -1 && idx + nidx < input.length) {
        //idx+nidx is the index of the last ")"
        idx += nidx;
        //The stack contains the index of the first "("
        startIdx = mStack.pop();
        foundMatches.push(input.substr(startIdx, idx + 1 - startIdx));
    }
    idx += 1;
}
于 2013-08-22T00:25:28.973 回答
1

您如何在没有正则表达式的帮助下使用循环自己解析它?这是一种简单的方法:

  • 你必须有一个变量,比如“level”,它记录你到目前为止遇到了多少个开括号(用 0 初始化它)。
  • 您还需要一个字符串缓冲区来包含每个匹配项(例如 (2+2) 或 (2+3 * (2+3)) )。
  • 最后,您需要在完成读取匹配时将缓冲区的内容转储到某个地方。

  • 当您逐个字符地读取字符串时,遇到“(”时将增加 1 级,遇到“)”时会减少 1 级。然后,您会将字符放入缓冲区。

  • 当您遇到“)”并且级别恰好达到 0 时,这就是您知道您有匹配项的时候。这是您转储缓冲区内容并继续的时候。

此方法假定只要您有一个“(”,输入字符串中总会有一个相应的“)”。此方法将处理任意数量的括号。

于 2013-08-22T00:24:22.843 回答