4

次の正規表現日付バリデータがありますが、次の日付を許可しています:

"99/99/2012"

理由がわかりません。正規表現を変更して上記を確認する方法を誰かが知っている場合

日付形式は次のとおりです: 06/05/2012 mm/dd/yyyy

正規表現:

^(((0?[1-9]|1[012])/(0?[1-9]|1\d|2[0-8])|(0?[13456789]|1[012])/(29|30)|(0?[13578]|1[02])/31)/(19|[2-9]\d)\d{2}|0?2/29/((19|[2-9]\d)(0[48]|[2468][048]|[13579][26])|(([2468][048]|[3579][26])00)))$
4

3 に答える 3

3

これらのパターンでは、複雑すぎることがたくさん見られます。日付形式は実際には非常に単純です。28 日の月と 31 日の月の重複を無視して、間違ったアプローチを取っていると思います。

これ以上説明する前に、正規表現に行き詰まっていない限り、日付を解析して検証するためのより良い方法があることを指摘させてください。最適なオプションは、このために作成されたDateTime.TryParseExactです。WebForms を使用している場合は、 と を使用して CompareValidator をドロップするだけです。Operator="DataTypeCheck"Type="Date"

魔法の言葉を言ったところで、正規表現パターンについて話しましょう。

これの見方を変えてください。すべての月に 31 日または 30 日が含まれるわけではありませんが、28 日を含む月はいくつありますか?

…全部!したがって、4 月と 5 月を一致させたい場合は、4 月 1 日から 30 日までと 5 月 1 日から 31 日までをカバーする必要はありません。いずれかの月の最初の 30 日間をカバーするパターンを作成し、その後 5 月 31 日に単独で到達することができます。結果は のようなもの[45]/([012]?[1-9]|[123]0)|5/31になり、そうでない場合の半分の長さになります。

わかりやすくするために拡張した次のパターンを考えてみましょう。

^(
( #First, we'll cover months and days for a normal year. Forget leap years 
  #for a second.
  (
     (?<month>0?[1-9]|1[012])      #First we account for up to 28 days,
     /(?<day>[01]?[1-9]|10|2[0-8]) #which ALL months have.
  )
  |
  (
     (?<month>0?[13-9]|1[012])     #Every month but February has at
     /(?<day>29|30)                #least 30 days, so cover that.
  )
  |
  (
     (?<month>0?[13578]|1[02])     #Cover the 31st day for months
     /(?<day>31)                   #that have one.
  )
)

/(?<year>(1[89]|20)[0-9]{2})  #Any year between 1800 and 2099.

|  #Normal years: Done. Now we just need to cover February 29, 
   #and only for leap years.

(?<month>0?2)
/(?<day>29)
/(?<year>
      (1[89]|20)      #Century doesn't matter, since 100 is divisible by 4.
      (
        [24680][048]  #If the decade is even, leap years end in [048].
      |                            
        [13579][26]   #If the decade is odd, leap years end in 2 or 6.
      )
  )
)$

これで完了です。mm/dd/yyyy 形式を強制し、既存の日付を検証します。短くて読みやすいです。縮小版は次のとおりです。

^(((0?[1-9]|1[012])/([01]?[1-9]|10|2[0-8])|(0?[13-9]|1[012])/(29|30)|(0?[13578]|1[02])/31)/(1[89]|20)[0-9]{2}|0?2/29/(1[89]|20)([24680][048]|[13579][26]))$

編集:

これは .NET であるため、ルックアラウンドを使用してかなり短縮できます。

 ^(
    (?!(0?[2469]|11)/31)
    (?!0?2/(29|30))
    (?<month>0?[1-9]|1[012])
    /
    (?!0?0/)
    (?<day>[012]?[0-9]|3[01])
    /
    (?<year>(1[89]|20)[0-9]{2})
  |
    (?<month>0?2)/(?<day>29)
    /
    #Years ending in 00 are only leap years if they're divisible by 400:
    (?!1[89]00)  
    (?<year>(1[89]|20) ( [24680][048] | [13579][26] ) )
 )$
于 2012-06-14T17:54:28.920 に答える
2

次の正規表現を使用できます。

  • MM/DD/YYYY フォーマット
  • 1800から9999までの任意の日付を検証します
  • うるう年の勘定科目
  • 受け入れられる形式: MM/DD/YYYY、M/DD/YYYY、MM/D/YYYY、M/D/YYYY

((^(10|12|0?[13578])([/])(3[01]|[12][0-9]|0?[1-9])([/])((1 [8-9]\d{2})|([2-9]\d{3}))$)|(^(11|0?[469])([/])(30|[12] [0-9]|0?[1-9])([/])((1[8-9]\d{2})|([2-9]\d{3}))$)| (^(0?2)([/])(2[0-8]|1[0-9]|0?[1-9])([/])((1[8-9]\d {2})|([2-9]\d{3}))$)|(^(0?2)([/])(29)([/])([2468][048]00) $)|(^(0?2)([/])(29)([/])([3579][26]00)$)|(^(0?2)([/])(29) ([/])( 1 [89][0][48])$)|(^(0?2)([/])(29)([/])([2-9][0-9 ][0][48])$)|(^(0?2)([/])(29)([/])( 1 [89][2468][048])$)|(^(0 ?2)([/])(29)([/])([2-9][0-9][2468][048])$)|(^(0?2)([/])( 29)([/])( 1 [89][13579][26])$)|(^(0?2)([/])(29)([/])([2-9][0 -9][13579][26])$))

はい、少し威圧的ですが、私は長年それを使用して大成功を収めてきました。

このオンライン式テスターを使用してテストできます。

楽しみ!

于 2012-06-14T17:01:09.843 に答える
2

考慮すべき別のオプションを捨てるだけです...

私は単純な正規表現が好きですが、クレイジーなものは検証と維持が困難です。

代わりに、独自のバリデーターを作成DateTime.TryParseExact()し、作業を行うために使用できますか?

詳細については、 http://msdn.microsoft.com/en-us/library/ms131044.aspxを参照してください。

(untested)

// this is inside a custom validator

DateTime d;

// get dateString from the control
if (DateTime.TryParseExact(dateString, 
                           "MM/dd/yyyy",
                           CultureInfo.InvariantCulture,
                           DateTimeStyles.None,
                           out d)
{
     // valid dateString
}
else
{
    // invalid dateString
}
于 2012-06-14T17:24:25.677 に答える