如何查看一个字符串是否包含关键字列表中的关键字?

时间:2011-12-29 13:49:35

标签: ruby

我想查看一个字符串是否包含关键字列表中的关键字。

我有以下功能:

def needfilter?(src)
    ["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"].each do |kw|
        return true if src.include?(kw)
    end
    false
end   

这段代码可以简化为一行句吗?

我知道它可以简化为:

def needfilter?(src)
    !["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"].select{|c| src.include?(c)}.empty?
end

但如果关键字数组列表很长,这种方法效率不高。

5 个答案:

答案 0 :(得分:3)

看起来像Enumerable#any?方法的一个很好的用例:

def needfilter?(src)
  ["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"].any? do |kw|
    src.include? kw
  end
end

答案 1 :(得分:1)

def need_filter?(src)
  !!(src =~ /keyowrd_1|keyowrd_2|keyowrd_3|keyowrd_4|keyowrd_5/)
end

=~方法返回fixnum或nil。双重爆炸将其转换为布尔值。

答案 2 :(得分:1)

我很好奇什么是最快的解决方案,我创建了迄今为止所有答案的基准。

我稍微修改了steenslag answer。出于调整原因,我只为每次测试创建一次正则表达式。

require 'benchmark'
KEYWORDS = ["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"]
TESTSTRINGS = ['xx', 'xxx', "keyowrd_2"]

N = 10_000 #Number of Test loops

def needfilter_orig?(src)
    ["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"].each do |kw|
        return true if src.include?(kw)
    end
    false
end 
def needfilter_orig2?(src)
    !["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"].select{|c| src.include?(c)}.empty?
end
def needfilter_any?(src)
  ["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"].any? do |kw|
    src.include? kw
  end
end
def needfilter_regexp?(src)
  !!(src =~ Regexp.union(KEYWORDS))
end
def needfilter_regexp_init?(src)
  !!(src =~ $KEYWORDS_regexp)
end
def needfilter_split?(src)
  (src.split(/ /) & KEYWORDS).empty?
end

Benchmark.bmbm(10) {|b|

  b.report('orig') { N.times { TESTSTRINGS.each{|src| needfilter_orig?(src)} } }
  b.report('orig2') { N.times { TESTSTRINGS.each{|src| needfilter_orig2?(src) } } }
  b.report('any') { N.times { TESTSTRINGS.each{|src| needfilter_any?(src) } } }
  b.report('regexp') { N.times { TESTSTRINGS.each{|src| needfilter_regexp?(src) } } }
  b.report('regexp_init') { 
   $KEYWORDS_regexp = Regexp.union(KEYWORDS) # Initialize once
    N.times { TESTSTRINGS.each{|src| needfilter_regexp_init?(src) } }
  }
  b.report('split') { N.times { TESTSTRINGS.each{|src| needfilter_split?(src) } } }

} #Benchmark

结果:

Rehearsal -----------------------------------------------
orig          0.094000   0.000000   0.094000 (  0.093750)
orig2         0.093000   0.000000   0.093000 (  0.093750)
any           0.110000   0.000000   0.110000 (  0.109375)
regexp        0.578000   0.000000   0.578000 (  0.578125)
regexp_init   0.047000   0.000000   0.047000 (  0.046875)
split         0.125000   0.000000   0.125000 (  0.125000)
-------------------------------------- total: 1.047000sec

                  user     system      total        real
orig          0.078000   0.000000   0.078000 (  0.078125)
orig2         0.109000   0.000000   0.109000 (  0.109375)
any           0.078000   0.000000   0.078000 (  0.078125)
regexp        0.579000   0.000000   0.579000 (  0.578125)
regexp_init   0.046000   0.000000   0.046000 (  0.046875)
split         0.125000   0.000000   0.125000 (  0.125000)

如果只创建一次正则表达式,那么使用正则表达式的解决方案是最快的。

答案 3 :(得分:1)

这就是我的方式:

def needfilter?(src)
    keywords = Regexp.union("keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5")
    !!(src =~ keywords)
end

此解决方案有:

  • 没有迭代
  • 使用Regexp.union
  • 的单一正则表达式

即使是大量的关键字也应该很快。请注意,对方法中的关键字进行硬编码并不理想,但我认为这仅仅是为了示例。

答案 4 :(得分:0)

我认为

def need_filter?(src)
  (src.split(/ /) & ["keyowrd_1","keyowrd_2","keyowrd_3","keyowrd_4","keyowrd_5"]).empty?
end

将按预期工作(如Array include any value from another array?中所述),并且会比any?include?更快。