感谢 Mark Wilkins 的启发,但这里有一小段代码:
irb(main):015:0> s = "split on the word on okay?"
=> "split on the word on okay?"
irb(main):016:0> b=[]; s.split(/(on)/).each_slice(2) { |s| b << s.join }; b
=> ["split on", " the word on", " okay?"]
或:
s.split(/(on)/).each_slice(2).map(&:join)
请参阅折叠下方的说明。
这是它的工作原理。首先,我们拆分“on”,但将其包裹在括号中以使其成为匹配组。当传递给split 的正则表达式中有匹配组时,Ruby 会在输出中包含该组:
s.split(/(on)/)
# => ["split", "on", "the word", "on", "okay?"
现在我们想将“on”的每个实例与前面的字符串连接起来。 each_slice(2) 通过一次将两个元素传递给它的块来提供帮助。让我们调用each_slice(2) 来查看结果。由于each_slice,在没有块的情况下调用时,将返回一个枚举器,我们将to_a应用于枚举器,这样我们就可以看到枚举器将枚举什么:
s.split(/(on)/).each_slice(2).to_a
# => [["split", "on"], ["the word", "on"], ["okay?"]]
我们越来越近了。现在我们所要做的就是将这些词连接在一起。这让我们得到了上面的完整解决方案。我将把它展开成单独的行以便于理解:
b = []
s.split(/(on)/).each_slice(2) do |s|
b << s.join
end
b
# => ["split on", "the word on" "okay?"]
但是有一个绝妙的方法可以消除临时的b 并大大缩短代码:
s.split(/(on)/).each_slice(2).map do |a|
a.join
end
map 将其输入数组的每个元素传递给块;块的结果成为输出数组中该位置的新元素。在 MRI >= 1.8.7 中,您可以将其进一步缩短到等效:
s.split(/(on)/).each_slice(2).map(&:join)