2

我刚刚阅读了有关Regexp.match?('string')Ruby 2.4 的信息,很高兴看到结果!但是当我在我的应用程序中尝试它时,我几乎没有看到任何收获。

str = 's'
Benchmark.bm do |b|
  b.report(".match         ") { 100000.times { 'string'.match /s/ } }
  b.report(".match?        ") { 100000.times { 'string'.match? /s/ } }
  b.report(".match dynamic ") { 100000.times { 'string'.match /#{str}/ } }
  b.report(".match? dynamic") { 100000.times { 'string'.match? /#{str}/ } }
end
                 user     system      total        real
.match           0.140000   0.000000   0.140000 (  0.143658)
.match?          0.020000   0.000000   0.020000 (  0.029628)
.match dynamic   0.370000   0.010000   0.380000 (  0.371935)
.match? dynamic  0.260000   0.010000   0.270000 (  0.278614)

.match从基准测试中,我们看到了to的巨大收益.match?,但是一旦我开始根据应用程序的需要动态创建复杂的正则表达式,我就会失去很多收益。

我的问题是,为什么会有如此巨大的差异,我可以以某种方式创建动态正则表达式来利用.matches?下面示例中的性能吗?我使用ruby 2.4.2p198

str = 'my text with words'
reg_str = '((^|[\s\"“])(cherry pie|cherry pies)($|[\s\"”\.\,\:\?\!])|(\#(cherrypie|cherrypies)($|\s|\#|\.|\,|\:|\?|\!)))'
puts Benchmark.measure {
  100000.times { str.match? /#{reg_str}/i }
}
9.380000   0.010000   9.390000 (  9.403821)

puts Benchmark.measure {
  100000.times { str.match? /((^|[\s\"“])(cherry pie|cherry pies)($|[\s\"”\.\,\:\?\!])|(\#(cherrypie|cherrypies)($|\s|\#|\.|\,|\:|\?|\!)))/i }
}  
0.020000   0.000000   0.020000 (  0.017900)
4

3 回答 3

4

使用/o修饰符,因此插值只执行一次:

str = 's'
Benchmark.bm do |b|
  b.report(".match         ") { 100000.times { 'string'.match /s/ } }
  b.report(".match?        ") { 100000.times { 'string'.match? /s/ } }
  b.report(".match dynamic ") { 100000.times { 'string'.match /#{str}/o } }
  b.report(".match? dynamic") { 100000.times { 'string'.match? /#{str}/o } }
end
       user     system      total        real
.match           0.120000   0.010000   0.130000 (  0.117889)
.match?          0.020000   0.000000   0.020000 (  0.027255)
.match dynamic   0.110000   0.000000   0.110000 (  0.113300)
.match? dynamic  0.030000   0.000000   0.030000 (  0.034755)
于 2018-05-22T18:42:17.830 回答
3

您基本上测量了字符串/正则表达式插值与文字实例化。时间match?本身并不影响测量的结果。

为了与 进行比较match?match应该预先实例化正则表达式:

str = 'my text with words'
reg_str = '...'
reg = /#{reg_str}/i
puts Benchmark.measure {
  100000.times { str.match? reg }
}

上述结果将与您的第二次测试大致相同。

也就是说,字符串/正则表达式插值是花费大部分时间的野兽。match?如果您需要在正则表达式中进行复杂的插值,则和之间的差异match不会很明显,因为插值是瓶颈,而不是匹配。

于 2018-05-22T19:07:12.420 回答
2

的速度提升match?来自于不分配 MatchData 对象和全局变量,例如$1. 它只是返回truefalsematch?如果您需要从正则表达式返回某些内容,则不能使用。

match?Regexp将正则表达式字符串编译成对象不会更快。

也许在您的代码中,您可以首先创建正则表达式,然后在循环中使用它们,而不是不断地重新创建它们:

# bad:
lines.each { |line| puts "Found a match!" if line.match?(/abcd/) }

# good:
regex = /abcd/
lines.each { |line| puts "Found a match!" if line.match?(regex) }
于 2018-05-23T09:01:24.137 回答