0

正規表現を使用して、特定のテキストを抽出してファイルを解析しようとしています。使用する必要のある正規表現は、標準パッケージではサポートされていません(ネストされた角かっこjava.util.regexなどのネストされた構造と一致させる必要があるため)。そこで、Perl5.6正規表現構文を完全に処理すると主張するを試してみることにしました。ただし、このパッケージを再帰的な正規表現で使用してネストされた角かっこを一致させようとすると、問題が発生しました。{}JRegex{}

Pattern p = new Pattern("(\\{(?:(?1)*|[^{}]*)+\\}|\\w+)");  // jregex.Pattern
スレッド"main"jregex.PatternSyntaxExceptionの例外: "(?":1の後の間違った文字

ただし、類似の正規表現/(\{(?:(?1)*|[^{}]+)+\}|\w+)/sgはPerlで期待どおりに機能します。それで、私の次のアイデアは、 Perlでファイルを解析し、その結果をJavaに渡す方法を見つけることでした(できれば文字列配列などの形式で)。私の質問は、それを行うための最良の方法は何ですか。この場合?または、私が見落としている別のより簡単な代替手段はありますか?

4

3 に答える 3

3

JRegexは再帰的マッチングをサポートしていないようです。そのためjava.util.regex、ネストのレベル数を使用して制限を設定することをお勧めします。

たとえば、各レベル(最も深いものを除く)に「無制限」の数のブラケットペアを使用して、最大50レベルのネストを許可するには、次のように使用できます。

// 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スクリプトを呼び出すにはどうすればよいですか?」などの回答を参照してください。それがあなたがやりたいことなら。

于 2013-03-09T16:50:15.630 に答える
1

最良の方法は、入力をトークン化し、トークンストリームを介してパーサーに送信し、必要に応じてトップダウン/ボットアップで解析することです。正規表現は、ネストされた構造の解析に常に役立つとは限りません。


JLexユーティリティは、Lex字句解析ジェネレータジェネレータモデルに基づいています。JLexは、Lexで受け入れられているものと同様の仕様ファイルを取得し、対応する字句アナライザーのJavaソースファイルを作成します。

非常に単純なコードからケースの字句アナライザーを生成するのに役立つ可能性があるため、JLexをご覧ください。

于 2013-03-09T13:02:40.013 に答える
0

正規表現は、ネストされた区切り文字を実際には処理できません。私は過去に、正規表現を使用して区切り文字を見つけ、次に単純な有限状態マシンを使用して結果の配列を解析することにより、これにアプローチしました。

于 2013-03-09T13:01:08.050 に答える