4

フォーマットの非常に単純な正規表現であるため、非常に奇妙dd/mmです。結果は次のようになるはずです"Group 1: 14; Group 2: 12"が、そうです"Group 1: 14; Group 2: 1"

2 番目のグループは最初の文字のみをキャプチャし、2 番目の文字 (例では「2」) を省略しました。

String sDay = "(?:0?[1-9]|[12][0-9]|3[01])";
String sMonth = "(?:0?[1-9]|1[0-2])";
String sDot = "[\\.]";
String sSlash = "[/]";
String sMinus = "[\\-]";
String sSeparators = (sDot + "|" + sSlash + "|" + sMinus);

Pattern reDayMonth =
    Pattern.compile("(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")");

String s = "14/12";
Matcher reMatcher = reDayMonth.matcher(s);
boolean found = reMatcher.find();

System.out.println("Group 1: " + reMatcher.group(1) + "; Group 2: " + reMatcher.group(2));

理由がわかりません。手伝っていただけませんか?

4

1 に答える 1

3

月の正規表現では、最初に1桁の数字が一致することを許可しているため、一致します(その後停止します)。必要な2桁の月を移動して、最初に確認してから1桁を確認してみてください

(?:0?[1-9]|1[0-2])

次のようになります。

(?:1[0-2]|0?[1-9])

UPDATE (推論)
パターン内で先頭にある同じパターンが機能するがパターン0?dayでは機能しない理由は、パターンmonthに従わなければならない文字があることを指定したためです。dayしたがって、のパターン全体dayが処理されます。ただし、このmonthパターンでは、後に続く文字は指定されていません。したがって、元のパターンでは1桁であった最初の一致が見つかると停止します。

入力形式を逆にして(つまり、dd/mm使用する代わりにmm/dd)、単純にスワップsDayしてコンパイルされた正規表現を使用すると、が2つの数値に正しく一致し、代わりに失敗することsMonthに実際に気付くでしょう。monthday

この問題を解決する1つの方法は、私の答えが示唆するように、最初に2文字のルールを照合し、次にオプションの1文字を照合することです。別の方法では、入力した日付がそれ自体で1行にあると想定/要求します(つまり、日付は行の先頭から始まり、他のテキストなしで行の終わりで終わります)。これが当てはまる場合は、正規表現^$文字を使用して、それぞれ行の最初と最後に一致させることができます。

Pattern.compile("^(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")$");

これを行うと、各パターンが完全に評価されて完全に一致するものが見つかります。この場合、常に正しい月/日と一致する必要があります。

サイトノート(提案、回答固有ではありません)
@MarkoTopolnikによる有用なコメント/提案によると、各グループ(月+日)の周りに非キャプチャグループを使用する必要はありません。特に、すぐにそれらをラップするためです。キャプチャグループは、非キャプチャグループを役に立たなくします。したがって、上記のパターンは単純に次のようになります。

1[0-2]|0?[1-9]
于 2012-10-25T12:48:51.130 に答える