在这种情况下,正则表达式比数组比较更快吗?

4

假设我有一个字符串,我想要扫描它以查看是否包含我选择的“坏”单词。 :)

将字符串拆分为数组,并将坏单词保存在另一个数组中,然后逐个遍历每个坏单词和每个输入单词,以查看是否存在匹配,这样做是否更快呢?

badwords.each do |badword|
 incoming.each do |word|
  trigger = true if badword == word
 end
end

还是这样做更快:

incoming.each do |word|
 trigger = true if badwords.include? word
end

还是将字符串保留原样并使用类似以下的正则表达式进行.match(),速度更快呢?

/\bbadword1\b|\bbadword2\b|\bbadword3\b/

或者性能差异几乎可以忽略不计?我一直在想这个问题。

8
停止猜测,开始测量。 - High Performance Mark
5个回答

5

当您在查找匹配项时,如果不在发现匹配项后停止循环,则正则表达式将具有优势。尝试使用以下代码:

incoming.find{|word| badwords.include? word}

我认为正则表达式仍然是最好的选择,应该简化为:

/\b(badword1|badword2|badword3)\b/

或者让它变成一场公平的较量:

/\a(badword1|badword2|badword3)\z/

1
你可以通过使用非捕获组来获得轻微的性能提升。 - Tim Pietzcker
太好了。你能告诉我为什么在 Ruby 文档的 Array#find 中没有列出 .find 作为一个方法吗? - dsp_099
是的,它是 Enumerable 模块的一部分,而 Array 包含了该模块。 - pguardiario

3

一旦编译完成,正则表达式在实时环境中(即长字符串、许多相似的不良词汇等)是最快的,因为它可以在 incoming in situ 上运行,并且能很好地处理重叠的 "bad words"。


2
答案可能取决于要检查的不良词汇数量:如果只有一个不良词汇,那么可能并没有太大的差别;但如果有50个,则使用数组进行检查可能会变慢。另一方面,对于数万或数十万个单词,使用正则表达式也可能不会太快。
如果您需要处理大量的不良词汇,您可能需要考虑将其分成单个单词,然后使用布隆过滤器来测试该单词是否可能是不良的。

2
这并不能完全回答你的问题,但一定可以帮助解决它。
举些例子来说明你要达到的目标,并将它们放到基准测试中。
你可以在这里找到如何在Ruby中进行基准测试的方法:这里
只需将各种形式放在报告块之间并获取基准测试结果,然后自行决定哪种最适合您。 http://ruby.about.com/od/tasks/f/benchmark.htm http://ruby-doc.org/stdlib-1.9.3/libdoc/benchmark/rdoc/Benchmark.html 为获得更好的解决方案,请使用真实数据进行测试。
基准测试总是比讨论更好 :)

1

如果您想要扫描字符串中的单词出现次数,请使用 scan 来查找它们。

使用 Regexp.union 构建一个模式,以查找黑名单中的字符串。您需要用 \b 包装结果以强制匹配单词边界,并使用不区分大小写的搜索。

为了让您了解 Regexp.union 如何帮助您:

words = %w[foo bar]

Regexp.union(words)
=> /foo|bar/

'Daniel Foo killed him a bar'.scan(/\b#{Regexp.union(words)}\b/i)
=> ["foo", "bar"]

如果你想要更多的控制,也可以使用Regexp.new/.../来构建模式:

Regexp.new('\b(?:' + words.join('|') + ')\b', Regexp::IGNORECASE)
=> /\b(?:foo|bar)\b/i

/\b(?:#{words.join('|')})\b/i
=> /\b(?:foo|bar)\b/i

'Daniel Foo killed him a bar'.scan(/\b(?:#{words.join('|')})\b/i)
=> ["Foo", "bar"]

作为一条建议,将您认为冒犯的词语列入黑名单是很容易被用户欺骗的,而且通常会得到错误的结果,因为许多“冒犯”的词语只有在特定的上下文中才是冒犯的。用户可以故意拼错它们或使用“l33t”语言,并拥有几乎无穷无尽的备选拼写方式,这将使您不断更新您的列表。对某些人来说,愚弄系统是一种乐趣。
我曾经接到过类似的任务,并编写了一个翻译器来提供“冒犯”词语的备选拼写。我从互联网上收集了一些词语和术语,并开始运行我的代码。在数据库中添加了数百万个备选项之后,我拔掉了插头,并向管理层展示了这是一个愚蠢的任务,因为很容易被愚弄。

好的提示。在我的情况下,我并没有过滤掉这些词语,而只是简单地扫描以查看是否有任何“-”符号,如果查询包含不良词汇,那么我将需要提供不同的结果。 - dsp_099

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