Regexp.last_match - 为什么有用?

时间:2017-04-02 10:10:50

标签: ruby regex

在“综合Ruby编程课程”电子书中,我遇到了一个章节,作者(Jordan Hudgens)描述了这一章:

“我们要尝试的最后一件事是返回句子中的所有整数值。”

他是这样做的:

string = "The quick 12 brown foxes jumped over 10 lazy dogs"
p string.to_enum(:scan, /\d+/).map { Regexp.last_match }

它返回:

=> [#<MatchData "3">, #<MatchData "34">, #<MatchData "23">]

我想知道为什么/何时,可以使用这个Regexp.last_match或更好地说 - 为什么这种方式不比以下方式更有效:

p string.to_enum(:scan, /\d+/).map { |i| p i } 

这只输出一个整数数组,对我来说似乎是一种更有效的方法来获取这些数字..

任何人都可以解释一下作者选择Regesp.last_match的原因可能是什么?

2 个答案:

答案 0 :(得分:1)

这是一个很好的技巧(读:hack)。

string = "The quick 12 brown foxes jumped over 10 lazy dogs"
p string.to_enum(:scan, /\d+/).map { Regexp.last_match }

事情是yieldMatchData String#scan p string.to_enum(:scan, /\d+/).map { |i| p i } 个实例没有方便的方法。

p string.to_enum(:scan, /\d+/).map(&:itself) # or { |i| i } # or .to_a

没有多大意义,你可能意味着:

p string.scan(/\d+/) 

甚至

extension Date {
    public var startOfQuarter: Date {
        let startOfMonth = Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!

        var components = Calendar.current.dateComponents([.month, .day, .year], from: startOfMonth)

        let newMonth: Int
        switch components.month! {
        case 1,2,3: newMonth = 1
        case 4,5,6: newMonth = 4
        case 7,8,9: newMonth = 7
        case 10,11,12: newMonth = 10
        default: newMonth = 1
        }
        components.month = newMonth
        return Calendar.current.date(from: components)!
    }
}

结果不同;后者返回 strings ,而前者是返回MatchData个实例的方法。

答案 1 :(得分:1)

如果你想要一个MatchData个实例的枚举器,这里有一个更详细但可能更清晰的解决方案:

class String
  def matches(regex)
    position = 0
    Enumerator.new do |yielder|
      while match = regex.match(self, position)
        yielder << match
        position = match.end(0)
      end
    end
  end
end

string = 'The quick 12 brown foxes jumped over 10 lazy dogs'
p string.matches(/\d+/).to_a
# [#<MatchData "12">, #<MatchData "10">]
p (2**1000000).to_s.matches(/(\d)\1{5}/).first(2)
# [#<MatchData "444444" 1:"4">, #<MatchData "888888" 1:"8">]

如果您不想使用String补丁,可以在Regex中定义此方法,也可以使用stringregex作为独立方法定义此方法作为参数。