【问题标题】:Regex date format less than operator正则表达式日期格式小于运算符
【发布时间】:2016-02-05 08:23:16
【问题描述】:

我正在尝试使用正则表达式来验证日期格式,我想检查日期是否小于 32。同样,月份也小于 12。我不知道该怎么做。目前,这就是我所拥有的;

^[0-1]?[0-9]{1}\-[0-3]?[0-9]{1}\-[0-9]{2,4}$

这个正则表达式实现格式 (m)m-(d)d-(yy)yy

【问题讨论】:

  • 您希望匹配的日期格式是什么?
  • 抱歉。 (m)m-(d)d-(yy)yy。这就是上面的正则表达式实现的格式。
  • 好的,请更新您的问题,谢谢
  • 我不确定正则表达式是否正确。即使匹配,因为日期小于 32 并且月份小于或等于 12,您仍然可能最终得到无效的日期:例如 02/30/16。我认为尝试使用 Date.strptime 解析字符串更有意义
  • 一般应该使用正则表达式来提取信息,而不是进行比较操作。不要这样自残。

标签: ruby regex


【解决方案1】:

TL;DR

不要使用正则表达式进行比较操作。使用正则表达式拆分值进行比较,或使用实际的解析器。

使用正则表达式提取可比对象

日期比较对于正则表达式来说是一个非常糟糕的问题。最多,您应该使用正则表达式来提取月份中的日期以进行数字比较。例如:

date = '01-01-1970'
date.split('-')[1].to_i < 32
#=> true

但是,上面的代码并不能真正告诉您给定日期是否有效。例如,2 月 30 日或 11 月 31 日呢?相反,您应该尝试解析日期以确定其有效性。

使用日期解析器

判断给定日期是否有效的最佳方法是使用日期解析器对其进行解析,然后报告布尔结果或处理异常。例如,您可以尝试使用Date#parse 解析日期。

布尔结果

如果你只想要一个布尔结果,你可以强制一个有效/无效的解析为真或假。例如:

require 'date'

date = '01-33-1970'
!!(Date.parse date rescue nil)
#=> false

抢救和报告异常

不那么神奇的是,您需要从 Date#parse 中拯救 ArgumentError。例如:

require 'date'

def valid_date? date_string
  true if Date.parse date_string
rescue ArgumentError => e
  STDERR.puts "#{e.class}: #{e}: '#{date_string}'"
  false
end

valid_date? '11-31-1970'

这将符合您的预期,尽管更加冗长。例如,上面的例子会将异常打印到标准错误中,然后返回 false 作为结果。

ArgumentError:无效日期:'11-31-1970'
#=> 错误

【讨论】:

  • 绝对使用类来解析和验证。正则表达式无法验证:Date.strptime('02-30-2001', '%m-%d-%Y') # ~&gt; ArgumentError: invalid date
【解决方案2】:
^(?:[0-1][1-2]|[1-9])\-(?:3[0-1]|[0-2][1-9]|[1-9])\-[0-9]{2}(?:[0-9]{2})?$

应该做你正在寻找的东西。它只允许从 1 到 12 的月份(1-9 或 01-12)、从 1 到 31 的天(1-9 或 01-31)以及至少 2 位数的年份,最多 4 位数。在 regex101 上测试。

【讨论】:

  • 确实如此。那是故意的。我在争论让它只匹配 2 位或 4 位数字,但在历史上已经有很多年了,3 位数字,所以我认为允许它不会破坏交易。
  • ^$ 在 Ruby 中分别是 line 的开始和结束,而不是 string。你几乎总是想要\A\z
【解决方案3】:

基本:

这是一个应该做你想做的正则表达式:

^(0[1-9]|1[0-2]|[1-9])-(0[1-9]|[1-2][0-9]|3[0-1]|[1-9])-\d{2}(\d{2})?$

它匹配大于 0 且小于 13 的月份,然后是 -,然后是大于 0 且小于 32 的天,然后是 -,然后是年份(2 位或 4 位)。

奖金:

完整的正则表达式,用于匹配该格式的日期并进行验证:

^((0?[13578]|10|12)-(([1-9])|(0[1-9])|([12])([0-9]?)|(3[01]?))-((19)([2-9])(\d{1})|(20)([01])(\d{1})|([8901])(\d{1}))|(0?[2469]|11)-(([1-9])|(0[1-9])|([12])([0-9]?)|(3[0]?))-((19)([2-9])(\d{1})|(20)([01])(\d{1})|([8901])(\d{1})))$

【讨论】:

  • 你的第一个不匹配个位数,第二个有太多的捕获组。 XD
  • @JohnClifford 已修复。即使它有太多的捕获组,它也能完美运行......
  • 我一直假设拥有大量捕获组会产生性能开销。公平地说,它可能不会。我在不需要在其他地方使用捕获的值的任何地方消除它们,但这可能只是我自己的怪癖,所以你是对的。
  • ^$ 在 Ruby 中分别是 line 的开始和结束,而不是 string。你几乎总是想要\A\z
  • 从技术上讲,第二个捕获mm/dd/yyyy 值,但它不会验证,因为它非常乐意接受02-30-2001。保持这样的模式比使用Date.strptime('02-30-2001', '%m-%d-%Y') # ~&gt; ArgumentError: invalid date 困难得多,因为Date.strptime('02-30-2001', '%m-%d-%Y') # ~&gt; ArgumentError: invalid date 会做正确的事情。
【解决方案4】:

如果你想确定字符串是一个有效的日期,你最好尝试转换它。如果它不会转换,它是无效的。

def date_valid?(date_string)
  format = '%m/%d/' + (date_string.split(-).last.size == 4 ? '%Y' : '%y')
  return true if Date.strptime(date_string, format)
  rescue ArgumentError
  return false
end

【讨论】:

    猜你喜欢
    • 2012-10-09
    • 2012-06-20
    • 1970-01-01
    • 2012-10-30
    • 2021-06-04
    • 1970-01-01
    相关资源
    最近更新 更多