13

コード

String s = "y z a a a b c c z";
Pattern p = Pattern.compile("(a )+(b )+(c *)c");
Matcher m = p.matcher(s);
while (m.find()) {
    System.out.println(m.group());
}

版画

a a a b c c

これは正しいです。

しかし、論理的には、部分文字列

a a a b c
a a b c c
a a b c
a b c c
a b c

正規表現にも一致します。

では、コードにこれらの部分文字列、つまり最も拡張された部分だけでなく、そのも検出させるにはどうすればよいでしょうか?

4

5 に答える 5

7

やなどの消極的な修飾子を使用できます。これらは、標準とは対照的に、可能な限り一致しません。これは貪欲です。つまり、可能な限り一致します。それでも、これはすべてではなく、特定の「サブマッチ」のみを見つけることができます。先読み制御の非キャプチャ グループを使用して、さらに制御を行うことができます。これについては、ドキュメントにも記載されています。しかし、すべてのサブマッチを実際に見つけるには、おそらく自分で何かを行う必要があります。つまり、正規表現が対応するオートマトンを構築し、カスタム コードを使用してナビゲートする必要があります。*?+?*+

于 2012-06-27T14:50:39.980 に答える
2

遅延量指定子が必要になります。

次のことを試してください。

Pattern p = Pattern.compile("(a )+(b )+((c )*?)c");

cまた、" " をもう一度グループ化したことに注意してください。そうしないと、任意の数のスペースが見つかりますが、" c" は見つかりません。

于 2012-06-27T14:49:00.877 に答える
0

すべての有効な一致を返すことができる正規表現エンジンを知りません。

しかし、少しのロジックを適用してすべての候補文字列を生成し、それを正規表現に提示することができます。

候補は、指定された入力の可能なすべての部分文字列を列挙することによって構築されます。

var str = "y z a a a b c c z y z a a a b c c z";
var regex = new Regex("(a )+(b )+(c *)c");

var length = str.Length;

for (int start = 1; start <= length;start++){

    for (int groupLength = 1;  start + groupLength - 1 <= length ;groupLength++){

        var candidate = str.Substring(start-1,groupLength); //.Dump();

        //("\"" + candidate + "\"").Dump();

        var match = regex.Match(candidate);

        if (match.Value == candidate )
        {
            candidate.Dump();
        }

    }
}

これは与える

a a a b c c 
a a b c c 
a b c c 

これは正しい答えのようですが、結果と矛盾します:

a a a b c => I state that this is not a match
a a b c c ok
a a b c => I state that this is not a match
a b c c ok
a b c => I state that this is not a match

たとえば、あなたが与える正規表現

(a )+(b )+(c *)c

結果の最初のエントリと一致しません

a a a b c 

開始位置が重要ではないと考える場合、上記のロジックは同一の一致を生成できます。たとえば、指定された入力をもう一度繰り返すだけの場合:

"y z a a a b c c z y z a a a b c c z"

それは与えます:

a a a b c c
a a b c c
a b c c
a a a b c c
a a b c c
a b c c

位置が重要ではないと考える場合は、この結果を区別する必要があります

一致する可能性があると見なされる場合は、入力が空の文字列である簡単なケースも追加する必要があります。

参考までに、これは正規表現が調べるすべての候補です

"y"
"y "
"y z"
"y z "
"y z a"
"y z a "
"y z a a"
"y z a a "
"y z a a a"
"y z a a a "
"y z a a a b"
"y z a a a b "
"y z a a a b c"
"y z a a a b c "
"y z a a a b c c"
"y z a a a b c c "
"y z a a a b c c z"
" "
" z"
" z "
" z a"
" z a "
" z a a"
" z a a "
" z a a a"
" z a a a "
" z a a a b"
" z a a a b "
" z a a a b c"
" z a a a b c "
" z a a a b c c"
" z a a a b c c "
" z a a a b c c z"
"z"
"z "
"z a"
"z a "
"z a a"
"z a a "
"z a a a"
"z a a a "
"z a a a b"
"z a a a b "
"z a a a b c"
"z a a a b c "
"z a a a b c c"
"z a a a b c c "
"z a a a b c c z"
" "
" a"
" a "
" a a"
" a a "
" a a a"
" a a a "
" a a a b"
" a a a b "
" a a a b c"
" a a a b c "
" a a a b c c"
" a a a b c c "
" a a a b c c z"
"a"
"a "
"a a"
"a a "
"a a a"
"a a a "
"a a a b"
"a a a b "
"a a a b c"
"a a a b c "
"a a a b c c"
"a a a b c c "
"a a a b c c z"
" "
" a"
" a "
" a a"
" a a "
" a a b"
" a a b "
" a a b c"
" a a b c "
" a a b c c"
" a a b c c "
" a a b c c z"
"a"
"a "
"a a"
"a a "
"a a b"
"a a b "
"a a b c"
"a a b c "
"a a b c c"
"a a b c c "
"a a b c c z"
" "
" a"
" a "
" a b"
" a b "
" a b c"
" a b c "
" a b c c"
" a b c c "
" a b c c z"
"a"
"a "
"a b"
"a b "
"a b c"
"a b c "
"a b c c"
"a b c c "
"a b c c z"
" "
" b"
" b "
" b c"
" b c "
" b c c"
" b c c "
" b c c z"
"b"
"b "
"b c"
"b c "
"b c c"
"b c c "
"b c c z"
" "
" c"
" c "
" c c"
" c c "
" c c z"
"c"
"c "
"c c"
"c c "
"c c z"
" "
" c"
" c "
" c z"
"c"
"c "
"c z"
" "
" z"
"z"

また、正規表現の 2 つの主なタイプ (NFA と DFA) がどのように機能するかを知っておくとよいでしょう。

http://msdn.microsoft.com/en-us/library/e347654k.aspxから

.NET (および私が思うに Java も) は (DFA とは対照的に) NFA 正規表現エンジンであり、特定の言語要素を処理するときに、エンジンは貪欲なマッチングを使用します。つまり、可能な限り多くの入力文字列に一致します。ただし、部分式の一致に成功した後も状態を保存します。最終的に一致が失敗した場合、エンジンは保存された状態に戻り、追加の一致を試みることができます。成功した部分表現の一致を破棄して、正規表現の後の言語要素も一致できるようにするこのプロセスは、バックトラッキングとして知られています。

于 2012-06-27T17:35:44.923 に答える
0

ここで考えられる唯一の方法は、元の文字列の可能なすべての部分文字列のリストを生成し、それらのそれぞれに対して正規表現を照合し、一致した項目を保持することです。

于 2012-06-27T15:28:32.287 に答える
-1

これらの非常に具体的な制約 (つまり、これは一般的なケースの解決策ではありません) を考えると、これは機能します。

import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class test {

    public static void main(String[] args) {

        String s = "y z a a a b c c z";

        Pattern p = Pattern.compile("(a )+(b )+(c ?)+");
        Set<String> set = recurse(s, p, 0);
    }

    public static Set<String> recurse(String s, Pattern p, int depth) {
        int temp = depth;
        while(temp>0) {
            System.out.print("  ");
            temp--;
        }
        System.out.println("-> " +s);

        Matcher matcher = p.matcher(s);
        Set<String> set = new TreeSet<String>();

        if(matcher.find()) {
            String found = matcher.group().trim();
            set.add(found);
            set.addAll(recurse(found.substring(1), p, depth+1));
            set.addAll(recurse(found.substring(0, found.length()-1), p, depth+1));
        }

        while(depth>0) {
            System.out.print("  ");
            depth--;
        }
        System.out.println("<- " +s);
        return set;
    }
}

他のケースで動作するように適応できると確信していますが、一致した文字列への再帰は、重複する一致 (@ahenderson によって指摘されたものなど) が機能しないことを意味します。

于 2012-06-27T17:17:18.850 に答える