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

本文关键字:字符串 一组 方法 另一个 查找 | 更新日期: 2023-09-27 18:30:48

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

根据这里另一个问题的一些建议,我制作了一个包含以下单词的哈希集:

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

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

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

swearWords.Contains(myString)

但这会返回错误。

检查哈希集中是否有任何单词在myString的最快方法是什么?

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

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

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

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

注意:HashSet<> 实现了 IEnumerable<>

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

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

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

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

  • 像那些使用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();

您可以将"myString"拆分为IEnumerable类型,然后在它们上使用"重叠"?

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

(附言好久不见...

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