C# - 在另一个字符串中查找一组字符串之一的最快方法

时间:2012-04-11 09:02:53

标签: c# .net regex string

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

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

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

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

我已经看到它反过来了,例如:

swearWords.Contains(myString)

但这会返回错误。

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

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

5 个答案:

答案 0 :(得分:10)

如果您将发誓放在IEnumerable&lt;&gt;中实施容器:

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

注意:HashSet&lt;&gt;实现IEnumerable&lt;&gt;

答案 1 :(得分:7)

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

Regex rx = new Regex("(" + string.Join("|", swearWords) + ")");
rx.IsMatch(myString)

答案 2 :(得分:7)

如果您有大量的咒骂词,您可以使用Aho-Corasick算法:http://tomasp.net/blog/ahocorasick.aspx

答案 3 :(得分:4)

此类方案的主要问题是定义您要检查的字符串上下文中的单词

  • 使用input.Contains的天真实现根本就没有单词的概念;他们会&#34;检测&#34;即使这不是意图,也要发誓。
  • 在空格上打破单词不会削减它(也可以考虑标点符号等)。
  • 打破空格以外的字符会引发文化问题:哪些字符被认为是单词字符?

假设您的禁用词列表仅使用拉丁字母,实际的选择是假设单词是仅由拉丁字符组成的序列。因此合理的起始解决方案将是

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。对于其他方法,请参阅this question以及可能接受的答案中提供的CodeProject链接。

分割输入字符串后,您可以迭代words并替换与列表中的任何内容匹配的内容(使用swearWords.Contains(word)进行检查)或者只是检测是否存在任何匹配

var anySwearWords = words.Intersect(swearWords).Any();

答案 4 :(得分:3)

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

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

(P.S。好久不见......)

编辑:刚刚在我之前的回答中发现错误。