12

ローマ数字の正規表現マッチャーを作成しようとしています。sed (正規表現の「標準」と見なされると思いますか?) では、代替演算子で区切られた複数のオプションがある場合、最も長く一致します。つまり、"I|II|III|IV"「IV」は「IV」、「III」は「III」に一致します。

Java では、同じパターンが「IV」の場合は「I」に、「III」の場合は「I」に一致します。Java は、左から右への交互一致のいずれかを選択することが判明しました。つまり、正規表現では「I」が「III」の前にあるため、一致します。正規表現を に変更する"IV|III|II|I"と、動作は修正されますが、これは明らかに一般的な解決策ではありません。

「最初」を選択する代わりに、代替グループからJavaに最長一致を選択させる方法はありますか?

わかりやすくするためのコード サンプル:

public static void main(String[] args)
{
    Pattern p = Pattern.compile("six|sixty");
    Matcher m = p.matcher("The year was nineteen sixty five.");
    if (m.find())
    {
        System.out.println(m.group());
    }
    else
    {
        System.out.println("wtf?");
    }
}

これは出力します"six"

4

2 に答える 2

20

いいえ、正しく動作しています。Javaは、NFA、またはPerl、.NET、JavaScriptなどの正規表現指向のフレーバーを使用します。sed、grep、awkとは異なります。代替案の1つが一致するとすぐに、最長の一致を保持するのではなく、代替案が終了することが期待されます。

トークン全体が消費されるまで満たすことができない条件を交代後に追加することで、強制的に続行させることができます。その条件がどうなるかは、コンテキストによって異なります。最も単純なオプションは、アンカー($)または単語境界(\b)です。

"\\b(I|II|III|IV)\\b"

編集:grep、sed、awkなどは伝統的にテキスト指向(またはDFA)エンジンを使用しますが、NFAエンジンを使用するバージョン、または2つのハイブリッドを使用するバージョンもあります。

于 2010-12-23T02:35:34.953 に答える
3

うまくいくパターンは次のようなものだと思います

IV|I{1,3}

http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.htmlの「貪欲な数量詞」セクションを参照してください。

編集:あなたのコメントに応えて、一般的な問題は、使用するのが適切でない場合に代替を使用し続けることだと思います. 新しい例では、「six」または「sixty」と一致させようとしています。使用する正しいパターンはsix(ty)?ではなくsix|sixtyです。一般に、代替グループに 2 つのメンバーがあり、一方が他方のプレフィックスになっている場合は、正規表現を書き直してそれを削除する必要があります。それ以外の場合、代替のセマンティクスは最長一致について何も述べていないため、エンジンが間違ったことをしていると文句を言うことはできません。

編集2:あなたの質問に対する文字通りの答えはノーです。強制することはできません(そして、私のコメントは、この動作は必要ないということです)。

編集 3: 主題についてもっと考えてみると、ある文字列が別の文字列のプレフィックスである交互パターンは、別の理由で望ましくないことがわかりました。つまり、基礎となるオートマトンがプレフィックスを考慮して構築されていない限り、遅くなります (Java がパターン内の最初の一致を選択することを考えると、そうではないと思います)。

于 2010-12-23T02:08:04.530 に答える