繁体   English   中英

使用正则表达式解析文本文件

[英]Parse text file with regular expression

我正在尝试使用正则表达式通过提取某些文本来解析文件。 标准java.util.regex软件包不支持我需要使用的正则表达式(因为我需要匹配嵌套的结构,例如嵌套的{}括号和其他类似的东西),所以我决定尝试JRegex ,它声称完全处理Perl 5.6 regex语法。 但是,在尝试将此包与递归正则表达式配合使用以匹配嵌套的{}括号时,我遇到了一个问题:

Pattern p = new Pattern("(\\{(?:(?1)*|[^{}]*)+\\}|\\w+)");  // jregex.Pattern
Exception in thread "main" jregex.PatternSyntaxException: wrong char after "(?": 1

但是,类似的正则表达式/(\\{(?:(?1)*|[^{}]+)+\\}|\\w+)/sg在Perl中可以正常工作。 因此,我的下一个想法是找到一种方法来解析Perl中的文件,然后将结果传递给Java (最好以字符串数组或类似的形式),而我的问题是:做到这一点的最佳方法是什么?在这种情况下? 或者,我还有其他更简单的选择吗?

JRegex似乎不支持递归匹配,因此我建议您只使用java.util.regex并设置嵌套级别的限制。

例如,要允许最多五十级嵌套,并且每一级上都有“无限”数量的括号对(最深的除外),您可以使用

// Set the maximum number of nested levels required.
int max = 50;
String regex = "(?R)";

while (--max > 0) {
    regex = regex.replace("(?R)", "(?>\\{(?:[^{}]*+|(?R))+\\})");
}

// Ensure no (?R) in the final and deepest replacement.
regex = regex.replace("(?R)", "\\{[^{}]*+\\}") + "|\\w+";

String str = " {{}{}} {abc} {{de}{fg}} hij {1{2{3{4{5{6{7{8{9{10{11{12{13{14{15{16{17{18{19{20{21{22{23{24{25{26{27{28{29{30{31{32{33{34{35{36{37{38{39{40{41{42{43{44{45{46{47{48{49{50}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} {end}";
Matcher m = Pattern.compile(regex).matcher(str);

while (m.find()) {
    System.out.println(m.group());
}

/*
 {{}{}}
 {abc}
 {{de}{fg}}
 hij
 {1{2{3{4{5{6{7{8{9{10{11{12{13{14{15{16{17{18{19{20{21{22{23{24{25{26{27{28{29{30{31{32{33{34{35{36{37{38{39{40{41{42{43{44{45{46{47{48{49{50}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
 {end}
*/

上面的方法通过使用一个可以支持递归匹配的正则表达式来构建正则表达式(?>\\\\{(?:[^{}]*+|(?R))+\\\\})然后重复替换(?R)代表整个模式。

因为在创建的表达式中有许多嵌套的量词,所以使用原子分组(?>)和所有格量词+来限制回溯,并确保如果找不到匹配项,则正则表达式会快速失败。 尽管正则表达式可能很长,但是它将很有效率。

如果您不想或无法设置嵌套限制,或者担心冗长的正则表达式,可以通过简单地遍历文件文本并跟踪打开和关闭括号的数量来解析嵌套的括号。 , 例如

List<String> list = new ArrayList<String>();
int strLen = str.length();

for (int i = 0; i < strLen; i++) {
    char c = str.charAt(i);

    if (c == '{') {
        int b = 1;
        StringBuilder sb = new StringBuilder("{");

        while (b > 0 && i < strLen - 1) {
            sb.append( c = str.charAt(++i) );

            if (c == '}') b--;
            else if (c == '{') b++;
        }
        list.add(sb.toString());
    }
}

for (String s : list) { System.out.println(s); }

这似乎比与Perl交互要麻烦得多,但是可以看到诸如“ 如何在Java中调用Perl脚本”之类的答案 如果那是你想做的。

最好的方法是对输入进行标记化,并通过标记流将其发送到解析器,然后根据需要自上而下/自底向上解析。 正则表达式并不总是有助于解析嵌套结构。


JLex实用程序基于Lex词法分析器生成器模型。 JLex获取与Lex接受的规范文件相似的规范文件,然后为相应的词法分析器创建Java源文件。

请看一下JLex,因为它可以帮助您从非常简单的代码中为案例生成词法分析器。

正则表达式不能真正处理嵌套定界符。 我过去通过使用正则表达式来查找定界符,然后使用简单的有限状态机来解析结果数组来解决此问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM