C# 如何从字符串中剪切指定的单词

C# 如何从字符串中剪切指定的单词,c#,algorithm,C#,Algorithm,这里有一个禁止使用的单词(或者更一般的字符串)列表,还有一个用户邮件列表。我想删除所有邮件中的所有禁用词 简单的例子: foreach(string word in wordsList) { foreach(string mail in mailList) { mail.Replace(word,String.Empty); } } 如何改进这个算法 谢谢你的建议。我投了几个赞成票,但我没有把任何一个作为答案,因为这更像是讨论而不是解决方案。有些人用脏话漏掉了禁

这里有一个禁止使用的单词(或者更一般的字符串)列表,还有一个用户邮件列表。我想删除所有邮件中的所有禁用词

简单的例子:

foreach(string word in wordsList)
{
   foreach(string mail in mailList)
   {
      mail.Replace(word,String.Empty);
   }
}
如何改进这个算法



谢谢你的建议。我投了几个赞成票,但我没有把任何一个作为答案,因为这更像是讨论而不是解决方案。有些人用脏话漏掉了禁止使用的词语。就我而言,我不必费心识别“sh1t”之类的东西。

简单的亵渎过滤方法不起作用-复杂的方法在大多数情况下也不起作用


当你得到一个像“密码”这样的工作,你想过滤掉“屁股”时会发生什么?如果某个聪明人改写“a$$”会发生什么-意图仍然很清楚,对吗


有关详细讨论,请参阅。

通过绘制(或生成)一个字符,然后一次解析输入的1个字符并遍历各个状态,您将获得最佳性能

使用一个函数可以很容易地实现这一点,该函数接受下一个输入字符和当前状态,并返回下一个状态,您还可以在遍历邮件消息的字符时创建输出。你在纸上画FSM

或者,你也可以研究一下这个问题


这样,您只需浏览每条消息一次。

您可以使用正则表达式使事情变得更干净:

var bannedWords = @"\b(this|is|the|list|of|banned|words)\b";

foreach(mail in mailList)
    var clean = Regex.Replace(mail, bannedWords, "", RegexOptions.IgnoreCase);

即使是这样,也不完美,因为人们总是在任何类型的过滤器周围找到一种方法。

你可以考虑使用<代码> ReXEX <代码>而不是简单的字符串匹配,以避免在单词中替换部分内容。正则表达式将允许您确保只获得匹配的完整单词。您可以使用如下模式:

"\bBADWORD\b"

此外,您可能希望在外部循环中遍历邮件列表,在内部循环中遍历单词列表。

从单词(
word1 | word2 | word3 |……
)构造正则表达式,使用此方法而不是外部循环可能会更快,因为从那时起,每封电子邮件只需要解析一次。此外,使用正则表达式将使您能够使用单词边界标记(
\b(word1 | word2 | word3 |……)\b
)仅删除“完整单词”


总的来说,我不认为你会找到一个比你现在的解决方案快几个数量级的解决方案:你必须循环浏览所有邮件,你必须搜索所有的单词,这不是一个简单的方法。

一个通用算法是:

  • 根据输入字符串生成令牌列表(即,将空格视为令牌分隔符)
  • 将每个标记与禁用单词列表进行比较
  • 替换匹配的令牌
  • 正则表达式可以方便地识别标记,而哈希集可以快速查找禁用词列表。在接受函数的
    Regex
    类上有一个重载的
    Replace
    方法,您可以根据查找来控制Replace行为

    HashSet<string> BannedWords = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
    {
        "bad",
    };
    
    string Input = "this is some bad text.";
    
    string Output = Regex.Replace(Input, @"\b\w+\b", (Match m) => BannedWords.Contains(m.Value) ? new string('x', m.Value.Length) : m.Value);
    
    HashSet BannedWords=新的HashSet(StringComparer.InvariantCultureIgnoreCase)
    {
    “坏”,
    };
    string Input=“这是一些错误的文本。”;
    字符串输出=Regex.Replace(输入,@“\b\w+\b”,(匹配m)=>BannedWords.Contains(m.Value)?新字符串('x',m.Value.Length):m.Value);
    
    将所有字符更改为
    *
    或其他方式来简单地对它们进行编辑不是更容易(也更有效)吗?这样一来,就不需要调整大字符串的大小或移动大字符串,而且接收者会更清楚发生了什么,而不是得到带有遗漏单词的无意义句子。

    将其替换为
    *
    很烦人,但是,比起那些通过删除单词并留下错误句子来删除你意图的上下文的事情来,它更不令人讨厌。在讨论黑斯廷斯之战时,如果我看到威廉被授予“诺曼底之王”,我会很恼火,但至少我知道我是在小孩子的游乐场上玩的,而他被授予“诺曼底之王”的头衔看起来是个错误,或者(更糟的)我可能会认为那实际上是他的头衔


    除非有趣,否则不要尝试用更无害的词来代替单词。人们在4chan上得到了这个笑话,但雅虎关于历史的小组却让人们感到困惑,因为中世纪和中世纪的评论取代了eval(不是亵渎,但在雅虎遭到的一些XSS攻击中使用)时,正在讨论medireview和mediareview时期(很明显,medireview是mediareview的美式拼写!)。

    好吧,你当然不想犯naive string.Replace()的错误。正则表达式解决方案可以工作,尽管你可以迭代或使用管道(我不知道这是否/多少会让你的操作慢下来,特别是对于一大堆被禁止的单词来说)。你总是可以……不这样做,因为不管怎样,这都是徒劳的——即使不使用确切的字母,也有办法让你想要的单词非常清楚

    这是很荒谬的,一开始就有一个“人们觉得冒犯”的单词列表。有人几乎会被任何一个单词冒犯


    /审查是胡说八道

    在某些情况下,可以改进它: 只是为了好玩:

    如果您的邮件列表是邮件列表,您可以使用SortedList(因为您有一个像“;”)这样的分隔符),您可以如下操作:

    首先计算ur运行时间算法: 单词:n个项目(每个项目有一个O(1)长度)。 邮件列表:K项。 邮件列表中的每个项目的平均长度为Z。 邮件列表项中的每个子项的平均长度为Y,因此邮件列表项中的子项的平均数量为m=Z/Y

    ur算法取O(n*K*Z)。//使用knut算法的最佳方法

    1.现在,如果你将单词列表按O(n log n)排序

    2.1-对每个邮件列表项使用mailingListItem.Split(;”.toCharray()):O(Z)