正则表达式匹配涉及上午/下午的时间范围,如上午 7 点至晚上 10 点

Posted

技术标签:

【中文标题】正则表达式匹配涉及上午/下午的时间范围,如上午 7 点至晚上 10 点【英文标题】:Regex to match time ranges involving am/pm like 7am-10pm 【发布时间】:2015-06-20 13:33:17 【问题描述】:

我写了下面的正则表达式

(1[012]|[1-9])(am|pm)\-(1[012]|[1-9])(am|pm)

匹配以下时间格式:

7am-10pm (matches correctly and creates 4 match groups 7, am, 10, pm)

13am-10pm (this should not be matched, however it matches and creates 4 match groups 3, am, 10, pm)

10pm (this doesn't match as expected because it doesn't specify the time range end)

111am-10pm (this should not be matched, however it matches and creates 4 match groups 11, am, 10, pm)

如何改进我的正则表达式,这样我就不需要重复数字和 am/pm 模式以及以下内容:

    它仅捕获时间范围组件,例如上午 7 点至上午 10 点应该只有 2 个匹配组,上午 7 点、上午 10 点。

    它只匹配正确的时间,例如上午 111 点或下午 13 点等应被视为不匹配。

    我不知道是否可以使用正则表达式,但我们可以让正则表达式匹配正确的时间范围,例如7am-1pm 应该匹配,但是 4pm-1pm 应该被视为不匹配?

注意:我使用的是 Ruby 2.2.1

谢谢。

【问题讨论】:

【参考方案1】:

首先让我们看看你做错了什么:

13am-10pm(这不应该匹配,但是它匹配并创建了 4 个匹配组 3、am、10、pm)

它只匹配适当的时间,例如上午 111 点或下午 13 点等应被视为不匹配。

这匹配,因为您允许在此处匹配单个数字 [1-9]:(1[012]|[1-9])。

为了解决这个问题,您应该允许一个 [1-9] 数字,或 1 + [0-2]。由于我们不知道正则表达式何时开始,我们将使用一些单词边界来确保我们有一个“单词开始”。

由于您不想捕获数字而是整个时间加上 am|pm,您可以使用非捕获组:

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

那么这只是重复我们自己并添加破折号的问题:

\b((?:1[0-2]|[1-9])[ap]m)-((?:1[0-2]|[1-9])[ap]m)

关于第 3 点。嗯,是的,您可以使用正则表达式执行此操作,但最好在获得第 1 组和第 2 组后简单地添加一个逻辑检查以查看时间范围是否真的有道理。

总而言之,这就是你得到的:

# \b((?:1[0-2]|[1-9])[ap]m)-((?:1[0-2]|[1-9])[ap]m)
# 
# 
# Assert position at a word boundary «\b»
# Match the regular expression below and capture its match into backreference number 1 «((?:1[0-2]|[1-9])[ap]m)»
#    Match the regular expression below «(?:1[0-2]|[1-9])»
#       Match either the regular expression below (attempting the next alternative only if this one fails) «1[0-2]»
#          Match the character “1” literally «1»
#          Match a single character in the range between “0” and “2” «[0-2]»
#       Or match regular expression number 2 below (the entire group fails if this one fails to match) «[1-9]»
#          Match a single character in the range between “1” and “9” «[1-9]»
#    Match a single character present in the list “ap” «[ap]»
#    Match the character “m” literally «m»
# Match the character “-” literally «-»
# Match the regular expression below and capture its match into backreference number 2 «((?:1[0-2]|[1-9])[ap]m)»
#    Match the regular expression below «(?:1[0-2]|[1-9])»
#       Match either the regular expression below (attempting the next alternative only if this one fails) «1[0-2]»
#          Match the character “1” literally «1»
#          Match a single character in the range between “0” and “2” «[0-2]»
#       Or match regular expression number 2 below (the entire group fails if this one fails to match) «[1-9]»
#          Match a single character in the range between “1” and “9” «[1-9]»
#    Match a single character present in the list “ap” «[ap]»
#    Match the character “m” literally «m»

【讨论】:

【参考方案2】:

您的正则表达式中缺少^(行首),这就是它在两者之间匹配的原因。

你必须使用:

^(1[012]|[1-9])(am|pm)\-(1[012]|[1-9])(am|pm)

更好的解决方案:如果您的模式并不总是从新行开始,您也可以使用\b(边界)。

\b(1[012]|[1-9])(am|pm)\-(1[012]|[1-9])(am|pm)\b

见DEMO。

【讨论】:

以上是关于正则表达式匹配涉及上午/下午的时间范围,如上午 7 点至晚上 10 点的主要内容,如果未能解决你的问题,请参考以下文章

Python 正则表达式匹配 OR 运算符

10月23日上午PHP数组

sqlserver 按一天时间段行转列 ([上午上班时间] [上午下班时间] [下午上班时间] [下午下班时间] )

如何在上午/下午 24 小时之间设置日期

2017年上半年软考心上午45下午55分!

9.26上午 JS表单验证+正则表达式