在这种情况下,Regex比数组比较更快吗?

时间:2012-09-02 06:59:08

标签: ruby regex arrays performance parsing

假设我有一个我要扫描的传入字符串,看它是否包含我选择的任何“糟糕”字样。 :)

将字符串拆分成数组更快,并将坏字保留在数组中,然后遍历每个坏字以及每个传入的字,看看是否有匹配,有点像: / p>

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/

或者性能差异几乎完全可以忽略不计?一直想知道这件事。

5 个答案:

答案 0 :(得分:5)

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

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

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

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

或使其公平对抗:

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

答案 1 :(得分:3)

一旦编译完成,正则表达式是实时最快的(即真正长的传入字符串,许多类似的坏字等),因为它可以在incoming in situ上运行并处理重叠部分你的"坏词"真的很好。

答案 2 :(得分:2)

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

如果您需要处理大量不良单词,您可能需要考虑拆分成单个单词,然后使用bloomfilter来测试单词是否可能是坏的。

答案 3 :(得分:2)

这并没有激动地回答你的问题,但这肯定有助于解决它。

举一些例子来说明你需要做些什么,然后把它们放到基准分数上。

您可以在ruby here

中找到如何进行基准测试

只需将varoius表单放在报告块之间并获得基准,并自行决定最适合您的方式。

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

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

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

基准总是优于讨论:)

答案 4 :(得分: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”发言并且几乎取之不尽的替代拼写可以让你不断更新你的列表。这是一些人欺骗系统的乐趣来源。

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