簡體   English   中英

C# - 在另一個字符串中查找一組字符串中的一個的最快方法

[英]C# - Fastest way to find one of a set of strings in another string

我需要檢查一個字符串是否包含任何臟話。

根據此處另一個問題的一些建議,我制作了一個包含以下文字的 HashSet:

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

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

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

swearWords.Contains(myString)

但這將返回 false。

檢查 HashSet 中的任何單詞是否在myString中的最快方法是什么?

注意:我想我可以使用 foreach 循環依次檢查每個單詞,如果找到匹配則中斷,我只是想知道是否有更快的方法。

如果將誓言放在 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);

上面的正則表達式是標准的 class \W修改為不包含數字; 有關詳細信息,請參閱http://msdn.microsoft.com/en-us/library/20bw873z.aspx 對於其他方法,請參閱此問題以及可能的已接受答案中提供的 CodeProject 鏈接。

拆分輸入字符串后,您可以遍歷words並替換與列表中任何內容匹配的單詞(使用swearWords.Contains(word)進行檢查)或簡單地檢測是否有任何匹配項

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

您可以將“myString”拆分為 IEnumerable 類型,然后對它們使用“Overlaps”嗎?

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

(PS好久不見……)

編輯:剛剛注意到我之前的回答中有錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM