在正则表达式中匹配小时/分钟/秒 - 更好的方法?

时间:2009-09-09 15:05:59

标签: regex language-agnostic

所以我需要从这些条目中获得数小时,分钟和秒钟:

  • 4时43分12秒
  • 9.43.12
  • 1:00
  • 01.04
  • 59
  • 09

前两个是小时,分钟和秒。 接下来是分钟和秒。 最后两个只是秒。

我想出了这个正则表达式,它有效..:

\A(?<hours>\d{1,2})(?::|\.)(?<minutes>\d{1,2})(?::|\.)(?<seconds>\d{1,2})\z|\A(?<minutes>\d{1,2})(?::|\.)(?<seconds>\d{1,2})\z|\A(?<seconds>\d{1,2})\z

但它很丑陋,我想重构它不是3种不同的表达方式(大多数只是为了学习)。我试过这个:

\A(?:(?<hours>\d{1,2})(?::|\.){0,1})(?:(?<minutes>\d{1,2})(?::|\.){0,1})(?:(?<seconds>\d{1,2}){0,1})\z

但这不起作用 - 分钟和秒钟有时会搞砸。我的大脑受伤了,我无法弄明白,我做错了什么。

4 个答案:

答案 0 :(得分:10)

我的建议:

(?:(?:(?<hh>\d{1,2})[:.])?(?<mm>\d{1,2})[:.])?(?<ss>\d{1,2})

结构:

(?:                     # group 1 (non-capturing)
  (?:                   #   group 2 (non-capturing)
    (?<hh>\d{1,2})      #     hours
    [:.]                #     delimiter
  )?                    #   end group 2, make optional
  (?<mm>\d{1,2})        #   minutes
  [:.]                  #   delimiter
)?                      # end group 1, make optional
(?<ss>\d{1,2})          # seconds (required)

如果您愿意,可以将正则表达式包装在分隔符中 - 例如单词边界\b或字符串锚点(^$)。

编辑:考虑一下,你可以进一步限制它,以捕捉有意义的时间。使用

[0-5]?\d

取代

\d{1,2}

仅在适当的情况下(秒和分钟)捕获0到59之间的值。

答案 1 :(得分:5)

我还没有对此进行测试,但它应该有效:

^(?:(?:(?<hours>\d\d?)[:\.])?(?<minutes>\d\d?)[:\.])?(?<seconds>\d\d?)$

编辑:
现在我测试了它并验证它是否有效。 :)

答案 2 :(得分:2)

我建议使用以下表达式。

^(((?<Hour>[0-9]{1,2})[.:])?(?<Minute>[0-9]{1,2})[.:])?(?<Second>[0-9]{2})$

这将允许单个数字小时与单个数字分钟相结合,如3:7:21。如果不需要,则需要稍作修改。

^(((?<Hour>[0-9]{1,2})[.:](?=[0-9]{2}))?(?<Minute>[0-9]{1,2})[.:])?(?<Second>[0-9]{2})$

第二个表达式中的正向前瞻断言(?=[0-9]{2})解决了这个问题。

答案 3 :(得分:1)

对此没有真正好的方法,因为它实际上取决于您的特定情况,当未指定所有三个部分时该怎么做。例如,在许多情况下,我可能更喜欢将3:30解释为3小时30分钟而不是3分30秒。它可以不明白这一点,并且很容易从正则表达式推导出这些输入意味着什么。

因此,我个人认为第一个正则表达式并不是那么难看 - 它可能不那么“神奇”,但它更具可读性和可维护性。确保您和其他人以后仍然可以阅读并更改代码!

如果您的语言支持,我会使用扩展的正则表达式(支持空格和注释)并将其拆分为三行(如果您在单独的行上放置注释,则为6或9)。这不会改变正则表达式,但肯定会让它感觉不那么难看。