检查字符串变量是否在一组字符串中

6

哪个更好:

x == 'abc' || x == 'def' || x == 'ghi'
%w(abc def ghi).include? x
x =~ /abc|def|ghi/

?


3
更好的方式是什么?可读性?可维护性?性能? - James
3个回答

7

哪个更好?这个问题不能轻易回答,因为它们并不总是做同样的事情。

x == 'abc' || x == 'def' || x == 'ghi'
%w(abc def ghi).include? x

比较x与固定字符串是否相等。 x必须是这些值之一。在这两个选项中,我倾向于选择第二个,因为它更容易维护。想象一下,如果您必须比较二十、五十或一百个字符串会是什么样子。

第三个测试:

x ~= /abc|def|ghi/

匹配子字符串:

x = 'xyzghi'
(x =~ /abc|def|ghi/) # => 3

所以它与前两者不同。

编辑:在nash进行的基准测试中,有一些我会做出不同选择的地方。在MacBook Pro上使用Ruby 1.9.2-p180,这个测试运行了100万次循环,并比较了锚定正则表达式、使用分组以及每次循环时不拆分%w()数组的结果:

require 'benchmark'
str = "test"

n = 1_000_000
Benchmark.bm do |x|
  x.report { n.times { str == 'abc' || str == 'def' || str == 'ghi' } }
  x.report { n.times { %w(abc def ghi).include? str } }
  x.report { ary = %w(abc def ghi); n.times { ary.include? str } }
  x.report { n.times { str =~ /abc|def|ghi/ } }
  x.report { n.times { str =~ /^abc|def|ghi$/ } }
  x.report { n.times { str =~ /^(abc|def|ghi)$/ } }
  x.report { n.times { str =~ /^(?:abc|def|ghi)$/ } }
  x.report { n.times { str =~ /\b(?:abc|def|ghi)\b/ } }
end
# >>       user     system      total        real
# >>   1.160000   0.000000   1.160000 (  1.165331)
# >>   1.920000   0.000000   1.920000 (  1.920120)
# >>   0.990000   0.000000   0.990000 (  0.983921)
# >>   1.070000   0.000000   1.070000 (  1.068140)
# >>   1.050000   0.010000   1.060000 (  1.054852)
# >>   1.060000   0.000000   1.060000 (  1.063909)
# >>   1.060000   0.000000   1.060000 (  1.050813)
# >>   1.050000   0.000000   1.050000 (  1.056147)

我知道。它应该使用 (?:...) 来避免捕获,并且还可以使用单词边界 /\b(?:abc|def|ghi)\b/。否则,原始问题的提出者需要理解这种差异,否则在某些时候会有一些需要追踪的错误。 - the Tin Man
@the Tin Man:如果你只是想获得真实性,为什么需要避免捕获呢? - Andrew Grimm
因为我相信,当处理正则表达式或任何可能产生副作用的东西时,写下我们所想的是一个好习惯。 - the Tin Man
1
/respond_to?/,因为它使用了未转义的'?',所以它可以匹配"respond_to"或"respond_t"。在正则表达式中,'?'的意思是“匹配前面的字符零次或一次”。在这个特定的例子中,它很可能不会有严重的副作用,因为我们没有一个名为"respond_t"的方法来引起混淆,但是对于其他被匹配的字符串,它可能会导致代码逻辑上的严重泄漏。适当的模式应该是使用respond_to\?,这将强制问号失去其“特殊性”并成为字面量。 - the Tin Man
我在工作中继承了一些代码,它在搜索模式中使用IP地址。八进制数之间嵌入的 "." 没有被转义,从而为每个匹配打开了三个漏洞,导致误匹配 - 这是一个严重的漏洞。 - the Tin Man
显示剩余4条评论

2

一些基准测试:

require 'benchmark'
str = "test"
Benchmark.bm do |x|
  x.report {100000.times {if str == 'abc' || str == 'def' || str == 'ghi'; end}}
  x.report {100000.times {if %w(abc def ghi).include? str; end}}
  x.report {100000.times {if str =~ /abc|def|ghi/; end}}
end

    user     system      total        real
0.250000   0.000000   0.250000 (  0.251014)
0.374000   0.000000   0.374000 (  0.402023)
0.265000   0.000000   0.265000 (  0.259014)

所以你可以看到,第一种方法比其他方法更快。而且字符串越长,最后一种方法的速度就越慢:

str = "testasdasdasdasdasddkmfskjndfbdkjngdjgndksnfg"
    user     system      total        real
0.234000   0.000000   0.234000 (  0.248014)
0.405000   0.000000   0.405000 (  0.403023)
1.046000   0.000000   1.046000 (  1.038059)

2

第一种方式可能会稍微快一些,因为它没有方法调用,而是直接进行字符串比较,但它也可能是最不易读和最难维护的。

第二种方式肯定是最酷的,也是使用Ruby的方式。它最易于维护,可能最容易阅读。

最后一种方式使用了老派的Perl正则表达式语法。速度相当快,维护起来不像第一种方式那么烦人,相当容易阅读。

我想这取决于你所说的“更好”是什么意思。


1
这是另一个由The Grimm Repairer修复的问题 :) @Andrew Grimm - Zabba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接