如何提取红宝石中的一部分线?

时间:2017-04-01 14:35:20

标签: ruby regex split

我有一句话说

  

line =" 2017年4月1日星期六07:30:37开始运行"

我要提取

  

" 2017年4月1日星期六07:30:37"

我试过了......

line = "start running at Sat April 1 07:30:37 2017"
if (line =~ /start running at/)
   line.split("start running at ").last
end

......但还有其他方法吗?

6 个答案:

答案 0 :(得分:4)

这是一种从任意字符串中提取表示给定格式的时间的子字符串的方法。我假设字符串中最多只有一个这样的子字符串。

require 'time'

R = /
    (?:#{Date::ABBR_DAYNAMES.join('|')})\s
              # match day name abbreviation in non-capture group. space
    (?:#{Date::MONTHNAMES[1,12].join('|')})\s
              # match month name in non-capture group, space
    \d{1,2}\s # match one or two digits, space
    \d{2}:    # match two digits, colon
    \d{2}:    # match two digits, colon
    \d{2}\s   # match two digits, space
    \d{4}     # match 4 digits
    (?!\d)    # do not match digit (negative lookahead)
    /x        # free-spacing regex def mode
  # /
  #  (?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s
  #   (?:January|February|March|...|November|December)\s
  # \d{1,2}\s
  # \d{2}:
  # \d{2}:
  # \d{2}\s
  # \d{4}
  # (?!\d)
  # /x 

def extract_time(str)
  s = str[R]
  return nil if s.nil?
  (DateTime.strptime(s, "%a %B %e %H:%M:%S %Y") rescue nil) ? s : nil
end

str = "start eating breakfast at Sat April 1 07:30:37 2017"
extract_time(str)
  #=> "Sat April 1 07:30:37 2017" 

str = "go back to sleep at Cat April 1 07:30:37 2017"
extract_time(str)
  #=> nil

或者,如果匹配R,但Time#strptime引发异常(意味着s不是给定时间格式的有效时间),可能会引发异常建议用户。

答案 1 :(得分:3)

line.sub(/start running at (.*)/, '\1')

答案 2 :(得分:2)

使用正则表达式执行此操作的标准方法是:

if md = line.match(/start running at (.*)/)
  md[1]
end

但是你不需要正则表达式,你可以做常规的字符串操作:

prefix = 'start running at '
if line.start_with?(prefix)
  line[prefix.size..-1]
end

答案 3 :(得分:1)

这是使用#partition的另一个选项(事实证明,稍快一点):

# will return empty string if there is no match, instead of raising an exception like split.last will
line.partition('start running at ').last

我感兴趣的是它如何对抗正则表达式匹配,所以这里有一个快速基准,每个执行100万次:

line.sub(/start running at (.*)/, '\1')
# => @real=1.7465

line.partition('start running at ').last
# => @real=0.712406
# => this is faster, but you'd need to be calling this quite a bit for it to make a significant difference

奖金:它也很容易满足更常见的情况,例如:如果你的行以&#34开头;开始在" 开始运行,而其他以&#34开头的行;停止在" 运行。然后像line.partition(' at ').last这样的东西将迎合两者(实际上运行得稍快)。

答案 4 :(得分:0)

最短的将是line["Sat April 1 07:30:37 2017"],这将返回你的"星期六2017年4月1日07:30:37"如果存在则为字符串,否则为nil。 String上的[]表示法是从字符串中获取子字符串的简写,可以与另一个字符串或正则表达式一起使用。见https://ruby-doc.org/core-2.2.0/String.html#method-i-5B-5D

如果字符串未知,您也可以像Cary建议的那样使用此简写

line[/start running at (.*)/, 1]

如果你想确定提取的日期是有效的,你需要他的答案中的正则表达式,但你仍然可以使用这种方法。

答案 5 :(得分:0)

还有另一种选择:

puts $1 if line =~ /start running at (.*)/