在Ruby中将字符串作为方法条件传递

3

有没有一种方法可以通过字符串操作创建条件呢?这是我尝试将字符串作为条件传递给include?方法的代码。

"hello eveyone in the house".include?(%w('hello' 'world' 'new\ york'    'place').join(" || ").to_s)
3个回答

4
include?函数只接受字符串作为参数,因此无法将条件语句作为参数传递给它。但是你可以编写类似以下的代码:
['hello', 'world', 'new york', 'place'].any? { |word|
  "hello everyone in the house".include?(word)
}

或者您可以从字符串生成正则表达式:

"hello eveyone in the house".match?(
  /#{['hello', 'world', 'new york', 'place'].join('|')}/
)

很好,但是在 Ruby < 2.4 中你必须使用 match,因为 match? 在之前的版本中不存在。 - peter
这是正确的,match? 是最近在 Ruby 2.4 中引入的。如果你使用的是旧版本,只需使用 match 即可。 - spickermann
不错。如果你只需要一个布尔值作为答案,使用 any? 的优点是它一旦发现字符串就停止执行。 - Eric Duminil
谢谢,看来我在尝试做一些不可能的事情。 - Jake Cooper

2
另一个可能性是对单词进行分割并使用集合交集:

split 方法可用于字符串分割,set intersection 方法可用于计算集合的交集:

sentence  = "hello everyone in the house"
whitelist = %w(hello world new-york place)

found_words = sentence.split & whitelist
p found_words        # => ["hello"]
p found_words.empty? # => false

警告:仅当白名单中不包含任何多个单词的字符串时才有效。例如,原问题中的new york

如需更健壮的解决方案,请参见@spickermann的答案。


1
这对于由多个单词组成的白名单术语(如此示例中的new york)是无效的。因为在句子new york中,它将被拆分为['new','york'],并且与数组[new york]不相交。 - spickermann

1

我进行了一些基准测试,以测试速度,令我惊讶的是,在Windows操作系统上,MRI Ruby 2.3.0中Spickerman的第一种解决方案是最快的,其次是交集,而我的解决方案使用Regexp.union却垫底了 :(

require 'benchmark' 

s = "hello everyone in the house"
a = ['hello', 'world', 'new york', 'place']

N = 10_000

Benchmark.bmbm do |x| 
  x.report("Union         ") { N.times { s.match(Regexp.union(a)) }}
  x.report("Union and scan") { N.times { s.scan(Regexp.union(a)) }}
  x.report("Interpollation") { N.times { s.match(/#{a.join('|')}/)}}
  x.report("intersect     ") { N.times { s.split & a }}
  x.report("block         ") { N.times { a.any? { |word| s.include?(word)}}}
end 

Rehearsal --------------------------------------------------
Union            0.110000   0.000000   0.110000 (  0.116051)
Union and scan   0.124000   0.000000   0.124000 (  0.121038)
Interpollation   0.110000   0.000000   0.110000 (  0.105943)
intersect        0.015000   0.000000   0.015000 (  0.018456)
block            0.000000   0.000000   0.000000 (  0.001908)
----------------------------------------- total: 0.359000sec

                     user     system      total        real
Union            0.109000   0.000000   0.109000 (  0.111704)
Union and scan   0.125000   0.000000   0.125000 (  0.119122)
Interpollation   0.109000   0.000000   0.109000 (  0.105288)
intersect        0.016000   0.000000   0.016000 (  0.017283)
block            0.000000   0.000000   0.000000 (  0.001764)

尝试将“helllo”放在a的末尾,看看这如何影响结果。目前为止,@spickerman的方法在处理完“hello”后就退出了,而其他方法则继续进行下去。 - Cary Swoveland
你需要编译 N 个正则表达式,可以将 Regexp.union 语句移到循环体外部,这样程序可能会更快。 - akuhn
我对这个结果并不感到惊讶。构建正则表达式并启动"正则表达式引擎"与简单的字符串操作和字符串比较相比非常昂贵。只有在像这样的简单用例中才值得使用,文本越长、条件越复杂或者多次重用同一个正则表达式,正则表达式的效益就越高。 - spickermann

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