【问题标题】:UK Date Regular Expression [duplicate]英国日期正则表达式 [重复]
【发布时间】:2013-12-19 16:58:49
【问题描述】:

我正在尝试创建一个验证英国日期格式的正则表达式。我有以下内容:

(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d

这非常适合验证:09/12/2011。但如果日期是:9/12/2011,它将无法正确验证。是否有一个正则表达式允许我在日期部分使用一个数字和两个数字?例如“09”和“9”。

【问题讨论】:

  • @Martinho:我认为 LooDaFunk 对正则表达式有很好的理解——他的正则表达式是有限的,但是是正确的。他坚持一个小细节,这正是人们选择 SO 的原因。
  • @Tim:我很难相信一个可以自己想出的人,至少不能想出([1-9]|0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d。但是,我可能是错的。
  • @Martinho:我很想深入学习正则表达式,但我没有时间了解它们的每一件事,然后回来做大部分更重要的工作跨度>
  • 我觉得两个地方的分隔符段应该是一样的:…([- /.])…\1…。相应地调整编号,或使用命名的捕获组。

标签: regex


【解决方案1】:

只需将前导 0 设为可选:

(0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012])[- /.](19|20)\d\d

不过,您将需要一个额外的验证步骤 - 此正则表达式当然不会检查无效日期,例如 31-02-2000 等。虽然可以在正则表达式中执行此操作,但不建议这样做,因为以编程方式执行此操作要容易得多,并且那个正则表达式将是可怕的。 Here is a date validating regex(不过,它使用 mmddyyyy 格式)来说明我的意思。

【讨论】:

  • 反正这个方法不是很正确,49也要匹配。
  • @pooh:不,不会。为什么你认为它会?
  • @Tim:它只会匹配“49/02/2010”,因为没有锚。但它也会匹配“今天是 04-02-2011”。
  • @Martinho:取决于你如何使用它——Java 中的Regex.Match(),Python 中的re.match() 等,许多验证器控件隐式地锚定了正则表达式。
  • @Tim:因为我试过了:)但是是的,这取决于风格和工具。
【解决方案2】:

我更喜欢将简单的正则表达式 (\d{1,2})[-/.](\d{1,2})[-/.](\d{4}) 与一些代码相结合,以验证这确实是一个正确的日期。无论如何,您都必须拥有该代码,除非您想创建一个拒绝“29-02-2011”但不拒绝“29-02-2008”的可怕正则表达式。

无论如何,这里是该正则表达式的细分,因此您可以看到发生了什么:

  • \d{1,2}:这部分匹配一个或两个 ({1,2}) 数字 (\d),构成日期的日部分。
  • [-/.]:匹配括号内的字符之一,即./-
  • \d{1,2}:同样,这与月份中的一位或两位数字匹配。
  • [-/.]: 另一个分隔符...
  • \d{4}:这与年份部分的四位 ({4}) 完全匹配。

请注意,正则表达式的日、月和年部分在括号内。这是为了创建。这三个部分中的每一个都将被捕获到一个组中,您可以从匹配中检索该组。组用一个数字标识,从左到右从 1 开始。这意味着日将是组 1、月组 2 和年组 3。还有一个组 0 始终包含匹配的整个文本。

您可以使用组来执行验证的第二部分并拒绝无效日期,例如“30-02-2011”、“31-4-2011”或“32-13-2011”。

如果您想拒绝使用两个不同分隔符的输入,例如“31-12.2011”,您可以使用一个更高级的功能,称为反向引用

(\d{1,2})([-/.])(\d{1,2})\2(\d{4})

请注意,现在我将第一个分隔符放在组内。这会将月份更改为第 3 组,将年份更改为第 4 组。分隔符与第 2 组匹配。反向引用是月份和年份之间的 \2 部分。它匹配前第二组匹配的任何内容。如果您从反向引用返回两个组,您最终会进入第 2 组,即分隔符。如果该组匹配.,则反向引用也仅匹配.;如果匹配-,则反向引用将仅匹配-;等等。

【讨论】:

  • 我希望我能理解为什么人们会发布长正则表达式的“故障”,而不是直接通过(?x) 模式将这些解释放入模式中。
  • @tchrist:主要是因为这样可读性差。它位于代码块内,这使得任何格式化的尝试都毫无意义,而等宽字体使行长得多。
  • 然后我可能还得解释一下(?x)...
  • 我总是发现(?x) 模式比没有的模式更清晰易读。这也是空白和对齐问题。我总是仔细地格式化它们。我认为它有帮助
【解决方案3】:

到底什么是“英国日期格式”?

今天是 2011 年 2 月 21 日,请参阅 BS EN 28601 / ISO 8601。

在网络上,你们都应该使用 RFC 3339 中定义的格式。

【讨论】:

  • 我们不拘泥于规则,做事不一样。
  • 我从未见过在现实生活中使用过这个例子。真实的人不会在这样的表格中输入日期。在英国,他们更喜欢 dd/mm/yy(yy),从不喜欢美国的方式,也从不喜欢 year first。当使用正则表达式检查日期格式时,我们需要检查用户自然会输入的内容,而不是 ISO 或 BS 或美国人认为他们应该输入的内容。当然,内部代码应该以统一和标准的方式管理日期,但要告诉大多数编程语言! Coldfusion 在这方面尤其糟糕。
【解决方案4】:

查看当天的正确方法是也禁止[4-9].号码。

类似0[0-9]|[12][0-9]|3[01]|[^0-9][0-9]|^[0-9]

【讨论】:

    【解决方案5】:

    是的。 {n,m} 是表示“至少 n 个元素,最多 m 个元素”的量词。所以你可以写\d{1,2}(匹配1或2位数字)。完成日期:\d{1,2}/\d{1,2}/\d{4}

    替代方案:使前导零可选:

    0?\d/0?\d/\d{4}
    

    问号表示,问号之前的元素是可选的。

    【讨论】:

      【解决方案6】:

      使用此代码,我正在验证日期的所有内容。 :-

      import java.util.regex.Matcher;
      import java.util.regex.Pattern;
      public class FinalDateValidator {
      
            private Pattern pattern;
            private Matcher matcher;
      
            public boolean isValidDate(final String date) {
                  Pattern pattern;
                  Matcher matcher;
                  final String DATE_PATTERN = "([0-9]{4})/(0?[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01]|[1-9])";
                  pattern = Pattern.compile(DATE_PATTERN);
                  matcher = pattern.matcher(date);
                  if (matcher.matches()) {
                      matcher.reset();
                      if (matcher.find()) {
                          int year = Integer.parseInt(matcher.group(1));
                          String month = matcher.group(2);
                          String day = matcher.group(3);
      
                           System.out.println("__________________________________________________");
                           System.out.println("year : "+year +"  month : "+month +" day : "+day);
      
                          if (day.equals("31")
                                  && (month.equals("4") || month.equals("6")
                                          || month.equals("9") || month.equals("11")
                                          || month.equals("04") || month.equals("06") || month
                                          .equals("09"))) {
                              return false; // only 1,3,5,7,8,10,12 has 31 days
                          } else if (month.equals("2") || month.equals("02")) {
                              // leap year
                              if (year % 4 == 0) {
                                  if (day.equals("30") || day.equals("31")) {
                                      return false;
                                  } else {
                                      return true;
                                  }
                              } else {
                                  if (day.equals("29") || day.equals("30")
                                          || day.equals("31")) {
                                      return false;
                                  } else {
                                      return true;
                                  }
                              }
                          } else {
                              return true;
                          }
                      } else {
                          return false;
                      }
                  } else {
                      return false;
                  }
              }
      
             public static void main(String argsp[]){
      
                 FinalDateValidator vs = new FinalDateValidator();
               System.out.println("1: 1910/12/10---"+vs.isValidDate("1910/12/10"));
                 System.out.println("2: 2010/2/29---"+vs.isValidDate("2010/02/29"));
                 System.out.println("3: 2011/2/29---"+vs.isValidDate("2011/02/29"));
                 System.out.println("3: 2011/2/30---"+vs.isValidDate("2011/02/30"));
                 System.out.println("3: 2011/2/31---"+vs.isValidDate("2011/02/31"));
                 System.out.println("4: 2010/08/31---"+vs.isValidDate("2010/08/31"));
                 System.out.println("5: 2010/3/10---"+vs.isValidDate("2010/03/10"));
                 System.out.println("6: 2010/03/33---"+vs.isValidDate("2010/03/33"));
                 System.out.println("7: 2010/03/09---"+vs.isValidDate("2010/03/09"));
                 System.out.println("8: 2010/03/9---"+vs.isValidDate("2010/03/9"));
                 System.out.println("9: 1910/12/00---"+vs.isValidDate("1910/12/00"));
                 System.out.println("10: 2010/02/01---"+vs.isValidDate("2010/02/01"));
                 System.out.println("11: 2011/2/03---"+vs.isValidDate("2011/02/03"));
                 System.out.println("12: 2010/08/31---"+vs.isValidDate("2010/08/31"));
                 System.out.println("13: 2010/03/39---"+vs.isValidDate("2010/03/39"));
                 System.out.println("14: 201011/03/31---"+vs.isValidDate("201011/03/31"));
                 System.out.println("15: 2010/032/09---"+vs.isValidDate("2010/032/09"));
                 System.out.println("16: 2010/03/922---"+vs.isValidDate("2010/03/922"));
      
             }
      
          }
      

      享受...

      【讨论】:

      • 问这个问题的人似乎在寻找一个正则表达式。在这种情况下,这对他根本没有帮助。
      • 29/02/2000 也不是闰年
      【解决方案7】:

      我遇到了类似的要求。 这是完整的正则表达式以及闰年验证。 格式:dd/MM/yyyy

      (3[01]|[12]\d|0[1-9])/(0[13578]|10|12)/((?!0000)\d{4})|(30| [12]\d|0[1-9])/(0[469]|11)/((?!0000)\d{4})|(2[0-8]|[01]\d| 0[1-9])/(02)/((?!0000)\d{4})| 29/(02)/(1600|2000|2400|2800|00)|29/(02)/(\d\d)(0[48]|[2468][048]|[13579][26])

      可以轻松修改为美国格式或其他欧盟格式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-06
        相关资源
        最近更新 更多