1

我需要在正则表达式中识别(可能嵌套的)捕获组并创建一棵树。特定的目标是 Java-1.6,我最好喜欢 Java 代码。一个简单的例子是:

“(a(b|c)d(e(f*g))h)”

这将被解析为

"a(b|c)d(e(f*g))h"
... "b|c"
... "e(f*g)"
     ... "f*g"

理想情况下,该解决方案应考虑计数表达式、量词等以及转义级别。但是,如果这不容易找到更简单的方法可能就足够了,因为我们可以限制使用的语法。

编辑。澄清。我想解析正则表达式字符串本身。为此,我需要知道 Java 1.6 正则表达式的 BNF 或等效项。我希望有人已经这样做了。

结果的副产品是该过程将测试正则表达式的有效性。

4

2 回答 2

1

考虑升级到实际的解析器/词法分析器: http ://www.antlr.org/wiki/display/ANTLR3/FAQ+-+Getting+Started

它看起来很复杂,但如果你的语言相当简单,它就相当简单。如果不是,在正则表达式中这样做可能会让你的生活变得地狱:)

于 2009-09-15T22:46:57.497 回答
1

我想出了一个使用 XML 工具(XOM,http ://www.xom.nu )来保存树的部分解决方案。首先是代码,然后是示例解析。首先,转义字符(\、(和))被反转义(这里我使用 BS、LB 和 RB),然后将剩余的括号转换为 XML 标签,然后解析 XML 并重新转义字符。进一步需要的是用于 Java 1.6 正则表达式 doe 量词的 BNF,例如 ?:、{d,d} 等。

public static Element parseRegex(String regex) throws Exception {
    regex = regex.replaceAll("\\\\", "BS");
    regex.replaceAll("BS\\(", "LB");
    regex.replaceAll("BS\\)", "RB");
    regex = regex.replaceAll("\\(", "<bracket>");
    regex.replaceAll("\\)", "</bracket>");
    Element regexX = new Builder().build(new StringReader(
         "<regex>"+regex+"</regex>")).getRootElement();
    extractCaptureGroupContent(regexX);
    return regexX;
}

private static String extractCaptureGroupContent(Element regexX) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < regexX.getChildCount(); i++) {
        Node childNode = regexX.getChild(i);
        if (childNode instanceof Text) {
            Text t = (Text)childNode;
            String s = t.getValue();
            s = s.replaceAll("BS", "\\\\").replaceAll("LB", 
                        "\\(").replaceAll("RB", "\\)");
            t.setValue(s);
            sb.append(s);
        } else {
            sb.append("("+extractCaptureGroupContent((Element)childNode)+")");
        }
    }
    String capture = sb.toString();
    regexX.addAttribute(new Attribute("capture", capture));
    return capture;
}

例子:

@Test
public void testParseRegex2() throws Exception {
    String regex = "(.*(\\(b\\))c(d(e)))";
    Element regexElement = ParserUtil.parseRegex(regex);
    CMLUtil.debug(regexElement, "x");
}

给出:

<regex capture="(.*((b))c(d(e)))">
  <bracket capture=".*((b))c(d(e))">.*
    <bracket capture="(b)">(b)</bracket>c
    <bracket capture="d(e)">d
      <bracket capture="e">e</bracket>
    </bracket>
  </bracket>
</regex>
于 2009-09-16T20:50:58.893 回答