6

我需要检查一个字符串是否包含任何脏话。

根据此处另一个问题的一些建议,我制作了一个包含以下单词的 HashSet:

HashSet<string> swearWords = new HashSet<string>() { "word_one", "word_two", "etc" };

现在我需要查看其中包含的任何值swearWords是否在我的字符串中。

我已经看到它以相反的方式完成,例如:

swearWords.Contains(myString)

但这将返回错误。

检查 HashSet 中的任何单词是否在中的最快方法是myString什么?

注意:我想我可以使用 foreach 循环依次检查每个单词,如果找到匹配项则中断,我只是想知道是否有更快的方法。

4

5 回答 5

10

如果你把你的誓言放在一个 IEnumerable<> 实现容器中:

var containsSwears = swarWords.Any(w => myString.Contains(w));

注意:HashSet<> 实现 IEnumerable<>

于 2012-04-11T09:05:18.317 回答
7

您可以尝试正则表达式,但我不确定它是否更快。

Regex rx = new Regex("(" + string.Join("|", swearWords) + ")");
rx.IsMatch(myString)
于 2012-04-11T09:06:21.217 回答
7

如果你有大量的脏话,你可以使用 Aho–Corasick 算法:http ://tomasp.net/blog/ahocorasick.aspx

于 2012-04-11T09:10:49.283 回答
4

这种方案的主要问题是在您要检查的字符串的上下文中定义一个词是什么

  • 幼稚的实现,例如使用input.Contains简单的实现,没有单词的概念;即使这不是意图,他们也会“发现”脏话。
  • 在空格上打断单词不会减少它(还要考虑标点符号等)。
  • 打破除空格以外的字符会引发文化问题:究竟哪些字符被认为是单词字符?

假设您的停用词列表仅使用拉丁字母,一个实际的选择是假设单词是仅由拉丁字符组成的序列。所以一个合理的起始解决方案是

var words = Regex.Split(@"[^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Pc}\p{Lm}]", myString);

\W上面的正则表达式是修改为不包含数字的标准类;有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/20bw873z.aspx。对于其他方法,请参阅此问题以及可能在接受的答案中提供的 CodeProject 链接。

拆分输入字符串后,您可以迭代words并替换与列表中任何内容匹配的那些(用于swearWords.Contains(word)检查)或简单地检测是否有任何匹配项

var anySwearWords = words.Intersect(swearWords).Any();
于 2012-04-11T09:20:37.410 回答
3

您可以将“myString”拆分为 IEnumerable 类型,然后对它们使用“Overlaps”?

http://msdn.microsoft.com/en-us/library/bb355623(v=vs.90).aspx

(PS好久不见……)

编辑:刚刚注意到我之前的回答中的错误。

于 2012-04-11T09:07:34.313 回答