Rubyのgsubとブロックと$1
何年かおきにはまる気がするこういうの:
def content
'aaabbbccc'
end
def content_gsub(regexp, repl = nil, &block)
if repl
content.gsub(regexp, repl)
else
content.gsub(regexp, &block)
end
end
regexp = /.(.)./
content_gsub(regexp, '[\1]') # => "[a][b][c]"
content_gsub(regexp) { "[#{$1}]" } # => "[][][]"
content_gsub(regexp) { '[\1]' } # => "[\\1][\\1][\\1]"
たまにこういう感じでgsub
しているライブラリがあって、うっかりはまった上にわりと回避策がない感じで困ったりする。
MatchDataを渡してくれるgsub
があるといいのかもなと時々思う。
def content_gsub2(regexp, repl = nil, &block)
if repl
content.gsub(regexp, repl)
else
content.gsub(regexp) { block.call($~) }
end
end
content_gsub2(regexp) { |m| "[#{m[1]}]" } # => "[a][b][c]"
yieldするとちょっと速いらしい。(Ruby 2.3.1)
def content_gsub3(regexp, repl = nil)
if block_given?
content.gsub(regexp) { yield($~) }
else
content.gsub(regexp, repl)
end
end
require 'benchmark/ips'
n = 1000
Benchmark.ips do |x|
x.report('gsub') do
n.times { content_gsub(regexp) { 'x' } }
end
x.report('gsub2') do
n.times { content_gsub2(regexp) { 'x' } }
end
x.report('gsub3') do
n.times { content_gsub3(regexp) { 'x' } }
end
x.compare!
end
いちおうこんな感じ:
Comparison:
gsub: 199.0 i/s
gsub3: 160.1 i/s - 1.24x slower
gsub2: 136.3 i/s - 1.46x slower
追記
@arika MatchDataを返すgsubは例によって名前問題
— †ꁐ𐨥ᐠ†-̱̏ (@n0kada) 2016年7月12日