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/

还是性能差异几乎可以忽略不计?想知道这个有一段时间了。

4

5 回答 5

5

通过在找到匹配项时不停止循环,您正在为正则表达式提供优势。尝试:

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

我的钱仍在正则表达式上,但应该简化为:

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

或者让它成为一场公平的战斗:

/\a(badword1|badword2|badword3)\z/
于 2012-09-02T08:33:54.000 回答
3

编译后,Regex 是现实生活中最快的(即非常长的传入字符串,许多类似的坏词等),因为它可以incoming 在原地运行,并且可以很好地处理“坏词”的重叠部分。

于 2012-09-02T07:10:48.217 回答
2

答案可能取决于要检查的坏词的数量:如果只有一个坏词,它可能不会产生太大的影响,如果有 50 个,那么检查一个数组可能会变慢。另一方面,对于数万或数十万个单词,正则表达式可能也不会太快

如果您需要处理大量坏词,您可能需要考虑拆分成单个词,然后使用布隆过滤器来测试该词是否可能是坏词。

于 2012-09-02T08:50:56.590 回答
2

这并不能完全回答您的问题,但这肯定有助于解决它。

举一些你想要达到的例子,并将它们作为基准。

你可以在这里找到如何在 ruby​​ 中进行基准测试

只需将各种表格放在报告块之间并获取基准并自行决定最适合您的方式。

http://ruby.about.com/od/tasks/f/benchmark.htm

http://ruby-doc.org/stdlib-1.9.3/libdoc/benchmark/rdoc/Benchmark.html

为了获得更好的解决方案,请使用真实数据进行测试。

基准总是比讨论更好:)

于 2012-09-02T09:40:36.587 回答
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”说话,并拥有几乎取之不尽的替代拼写,这将使您不断更新您的列表。对某些人来说,愚弄系统是一种乐趣。

我曾经接到过类似的任务,并写了一个翻译器来为“冒犯性”单词提供替代拼写。我从从 Internet 上收集到的单词和术语列表开始运行我的代码。在向数据库添加了数百万个替代项之后,我拔掉了插头并向管理人员表明这是一项愚蠢的任务,因为愚弄它是微不足道的。

于 2012-09-03T06:10:25.913 回答