用正则表达式查找小时和分钟(如果它们在那里)

时间:2014-02-20 05:01:00

标签: ruby regex

我有以下潜在的字符串:

最多200小时

最多13小时40分钟 ...

现在我可以找到以下正则表达式的小时数:

/Up to (\d+) h/.match("Up to 200 h")

然而,对于其他类型的入口,我也可以有分钟,我没有看到如何建立正则表达式。

最后我希望总持续时间以分钟为单位,所以:

Up to 200 h ---> 200*60
Up to 13 h 40 min ---> 13*60 + 40

3 个答案:

答案 0 :(得分:1)

使用可选组((...)?):

m = /Up to (\d+) h\b(?: (\d+) min)?/.match('Up to 200 h')
# => #<MatchData "Up to 200 h" 1:"200" 2:nil>
m[1]
# => "200"
m[2]
# => nil
m[1].to_i * 60 + m[2].to_i
# => 12000

m = /Up to (\d+) h\b(?: (\d+) min)?/.match('Up to 13 h 40 min')
# => #<MatchData "Up to 13 h 40 min" 1:"13" 2:"40">
m[1]
# => "13"
m[2]
# => "40"
m[1].to_i * 60 + m[2].to_i
# => 820

m = /Up to (\d+) h\b(?: (\d+) min)?/.match('Up to 3 hippopotamuses')
# => nil

答案 1 :(得分:1)

这有效(但故意不确保该行开始或包含“最多”):

_, h, _, m = s.match(/(?:^|\s)(\d+)\s+h(\s+(\d+)\s+min)?(?:\s|$)/).to_a

s = "Up to 13  h abc"
_, h, _, m = s.match(/(?:^|\s)(\d+)\s+h(\s+(\d+)\s+min)?(?:\s|$)/).to_a
  #=> [" 13  h ", "13", nil, nil]
  # h => "13", m => nil

s = "Time until   13 h 40  min"
_, h, _, m = s.match(/(?:^|\s)(\d+)\s+h(\s+(\d+)\s+min)?(?:\s|$)/).to_a
  # => ["13 h  40  min", "13", "  40  min", "40"]
  # h => "13", m => "40"

s = "I was chased by 3 hippopotamuses"
_, h, _, m = s.match(/(?:^|\s)(\d+)\s+h(\s+(\d+)\s+min)?(?:\s|$)/).to_a
  #=> []
  • (?:..)表示非捕获组。一开始就有一个,最后一个。开头的那一个后面是捕获组1,它捕获第一个数字串(?:^|\s)(\d+)。这些数字前面必须是行首(^)或(|)空白字符(\s)。

  • 第一组捕获的数字字符串必须后跟一个或多个空白字符,然后是字母h(但不会捕获)。

  • h(\s+(\d+)\s+min)?后跟踪群组2。由于最后的问号,如果可能,将进行捕获,但正则表达式不需要成功。这是因为会议纪要可能存在,也可能不存在。

  • 此捕获组包含捕获组3 (\d+),捕获组分钟值(如果捕获2已生成)。数字前面必须至少有一个空白字符,后跟至少一个空白字符,然后是"min"

  • 如果捕获组2和3(分钟)进行捕获,则非捕获组(?:\s|$)要求min后跟空格或行尾。

  • 如果捕获组2和3未进行捕获,(?:\s|$)要求字母h后跟空格或行尾。

  • "Time until 13 h 40 min".match(/.../).to_a返回数组

#=> ["13 h  40  min", "13", "  40  min", "40"]

其中“13”,“40分钟”和“40”分别由组1,2和3捕获。由于我们需要捕获1和3,我们设置

_, h, _, m = s.match(/.../).to_a  

答案 2 :(得分:0)

或者您可以在正则表达式中使用替代运算符(或),如下所示:

(\d+ h|\d+ min)

或包括这样的秒:

(\d+ h|\d+ min|\d+ sec)

这是一个“全局”匹配,所以在ruby中你使用.scan()就像这样:

$m = "Up to 13 h 40 min 5 sec".scan(/(\d+ h|\d+ min|\d+ sec)/)

然后使用条件(如果那样)检查m [1],m [2],m [3]。