簡體   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