最長のサンプル文字列の「arg」値の 1 つは で?b?
、説明と一致していないようです。それを削除すると、正規表現はすべてのサンプルに一致しますが、それでも個々の引数を抽出するという問題が残ります。Java でこれを行う最も簡単な方法は、すべての引数を 1 つの文字列としてキャプチャし、その文字列を分割して個々の引数を分割することです。
@Tomalakが言ったように、あなたの正規表現はかなり良いです。私が間違っていると思う唯一のことは?
、最初の引数を表すグループの後です。最初の引数だけでなく、引数文字列全体を制御する必要があります。つまり、最初の引数がなければ、2 番目、3 番目などを探しても意味がありません。これが私がそれを行う方法です:
(?:[?]?[a-zA-Z0-9]+(?:,[?]?[a-zA-Z0-9]+)*)?
これは、何も一致しないか、1 つの引数、またはコンマで区切られた複数の引数に一致しますが、正規表現のように(たとえば),a
またはに一致しません。,?a,b
Java 文字列リテラルの形式の完全な正規表現を次に示します。
"([a-zA-Z]+)\\(((?:\\??[a-zA-Z0-9]+(?:,\\??[a-zA-Z0-9]+)*)?)\\)"
述語名はグループ #1 に取り込まれ、引数はグループ #2 に取り込まれます。引数がない場合、グループ #2 には空の文字列 ( ではないnull
) が含まれます。それ以外の場合は、コンマで分割することにより、個々の引数を分割できます。
\?
ところで、ほとんどのメタ文字はバックスラッシュ ( ) または角括弧 ( )でエスケープできます[?]
。両方を行う必要はありません。それが 1 文字だけの場合 (つまり、 のような実際の文字クラスの一部ではない場合[!.?]
)、バックスラッシュを使用することをお勧めします。Java と同じ文字数であることはわかっていますが、バックスラッシュを使用すると、もう少し自己文書化できると思います。
編集:これが私が使用したコードです:
String[] inputs = { "p()", "p(?a)", "p(?a,?b,c,?d)", "p(a,b,c)" };
Pattern p = Pattern.compile(
"([a-zA-Z]+)\\(((?:\\??[a-zA-Z0-9]+(?:,\\??[a-zA-Z0-9]+)*)?)\\)");
for ( String s : inputs )
{
Matcher m = p.matcher(s);
if ( m.matches() )
{
System.out.printf("%nFull match: %s%nPredicate name:%n %s%n",
m.group(), m.group(1));
String allArgs = m.group(2);
if (allArgs.length() == 0)
{
System.out.println("No arguments");
}
else
{
System.out.println("Arguments:");
for (String arg : allArgs.split(","))
{
System.out.printf(" %s%n", arg);
}
}
}
}