簡體   English   中英

我的正則表達式可以改進嗎?

[英]Can my Regex be improved?

是的, 另一個正則表達式問題。 不客氣的;-P

這是我第一次在C#中編寫自己的正則表達式進行簡單的字符串驗證。 我想我已經有了它的工作,但作為一個學習練習,我想知道它是否可以改進,我是否犯了任何錯誤。

字符串將看起來像這樣:

T20160307.0001

規則:

  • 從字母T開始。
  • 日期格式為YYYYMMDD。
  • 一個句號。
  • 最后4個字符始終為數字。 應該有4個。

這是我的正則表達式( 小提琴 ):

^(?I)[T] 20 [0-9] {2} [0-1] [0-9] [0-3] [0-9]。\\ d {4} $

  • ^斷言字符串的開頭。
  • (?i)[T]檢查我們是否有字母T,不區分大小寫。
  • 20 YYYY從20開始(我將在2100年前去世,所以我不在乎任何事情:-P)
  • [0-9]{2} YYYY第二部分的0到99之間的任意數字。
  • [0-1][0-9] 0或1表示月份的第一部分,0-9表示月份的第二部分。
  • [0-3][0-9] 0-3為第一天的部分,0-9為第二部分。
  • . 完全停止。
  • \\d{4} 4個數字字符。
  • $斷言字符串結尾。

我已經看到的一個陷阱是日期驗證。 2016 - 1935年(第19個月的第35天)被視為有效。 我已經閱讀了一些 / 其他 /關於實現這一點的帖子 ,我認為這與數字范圍匹配,但我無法理解格式。

我會接受一個簡單解決日期問題的答案,如果有人能夠對ELI5如何運作,那么其他改進將是一個值得歡迎的獎勵。

編輯:為了避免進一步混淆,我應該聲明我知道DateTime.TryParse等。如上所述,我正在利用這個作為學習正則表達式的機會,並認為這是一個很好的起點。 對於任何浪費時間的人都很抱歉,我應該在原帖中說清楚。

你可以做的事情是:

  • 避免匹配所有unicode數字的\\d字符類(因為你只需要ascii數字)
  • 而不是[0-1]你可以寫[01]
  • 逃避點來形成一個文字點(而不是任何字符)
  • 如果它是唯一的字符,則無需將T放入字符類中
  • 最終你可以刪除內聯修飾符並使用[Tt]代替T


^(?i)T20[0-9]{2}[01][0-9][0-3][0-9]\.[0-9]{4}$

要么

^[Tt]20[0-9]{2}[01][0-9][0-3][0-9]\.[0-9]{4}$

其他的事情:你真的需要添加額外的日期檢查,因為你無法真正測試日期格式是否正確? (想一想閏年)所以為什么不:

^(?i)T(20[0-9]{6})\.[0-9]{4}$

如果您想知道日期是否真的存在,請捕獲它並使用DateTime.TryParse方法對其進行測試。

為什么甚至使用Regex只使用DateTime.TryParseExact方法。 我會這樣實現它,並對其他字符進行額外檢查:

bool IsCorrectFormat(string input)
{
    //14 is a magic number for the length of the expected format
    if (input.Length == 14 && input.StartsWith("T", StringComparison.OrdinalIgnoreCase))
    {
        DateTime dt;
        if (DateTime.TryParseExact(input.Substring(1), "yyyyMMdd.ffff", CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
        {
            return true;
        }
    }

    return false;
}

我不知道格式是否正確但你總是可以從1到6子串獲得yyyyMMdd然后檢查最后5個字符的小數點和數字。

編輯:如果必須使用正則表達式

我過去曾使用過這個正則表達式。 請注意,它不會檢查閏年

@"^(((0[1-9]{1}|[1-2][0-9]{1}|3[01]{1})(0[13578]{1}|1[12]{1}))" //For a 31 day month
+ @"|"
+ @"((0[1-9]{1}|[1-2][0-9]{1}|30)(0[469]{1}|11))" //For a 30 day month
+ @"|"
+ @"((0[1-9]{1}|1[0-9]{1}|2[0-8]{1})(02)))" //For a 28 day month(feb)
+ @"([0-9]{4})$"; //For the year

如上所述,我將此作為學習正則表達式的機會,並認為這是一個很好的起點。

使用正則表達式驗證日期肯定不是一件容易的事情,特別是考慮到閏年所涉及的復雜規則。 但這是可能的。

如果以YYYYMMdd格式輸入有效日期,則以下表達式將匹配:

(?=\p{IsBasicLatin}{8}) # ensures \d matches only 0-9
(?!0000)\d{4} # year any 4-digit year, except 00
(?:0[1-9]\d|1[012]) # month 01-12
(?: 
   # day logic for leap years
   (?:
      (!00)[012]\d # Days 01-29 (we exclude 2/29 later)
      | (?<!02)30  # Day 30 valid for all months except Feb
      | (?<=0[13578]|1[02])31 # Day 31 valid for some months
   )
   # Non-Leap-year logic.  Do not allow 2/29 if the provided year
   # is not a leap year.
   (?<!
     (?:
        [13579] # years ending with odd number are not leap years
        | [02468][26]|[13579][048] # years not divisible by 4
                                     # are not leap years (02, 06, 10, ...)
        | (?:[02468][\d-[048]]|[13579][\d-[26]])00 # years divisible by
                                                 # 100 are not leap years,
                                                 # unless divisible by 400

     )0229)
)

使用RegexOptions.IgnorePatternWhitespace編譯。 你可以使用^T~\\.\\d{4}$匹配你的例子中的完整字符串,用上面的表達式替換~

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM