从字符串列表中删除子字符串

本文关键字:字符串 删除 列表 | 更新日期: 2023-09-27 18:30:26

我有一个包含禁用单词的字符串列表。检查字符串是否包含任何禁止单词并将其从字符串中删除的有效方法是什么?目前,我有这个:

cleaned = String.Join(" ", str.Split().Where(b => !bannedWords.Contains(b,
                            StringComparer.OrdinalIgnoreCase)).ToArray());

这适用于单个禁用词,但不适用于短语(例如 more than one word)。还应删除任何more than one word实例。我想尝试的另一种方法是使用 List 的 Contains 方法,但这只返回一个布尔值,而不是匹配单词的索引。如果我能得到匹配单词的索引,我就可以使用String.Replace(bannedWords[i],"");

从字符串列表中删除子字符串

一个简单的String.Replace将不起作用,因为它会删除单词部分。如果"性"是一个被禁止的词,而你有"六重奏"这个词,它没有被禁止,你应该保持原样。

使用Regex您可以在文本中找到整个单词和短语

string text = "A sextet is a musical composition for six instruments or voices.".
string word = "sex";
var matches = Regex.Matches(text, @"(?<='b)" + word + @"(?='b)");

在这种情况下,匹配集合将为空。

您可以使用Regex.Replace方法

foreach (string word in bannedWords) {
    text = Regex.Replace(text, @"(?<='b)" + word + @"(?='b)", "")
}

注意:我使用了以下Regex模式

(?<=prefix)find(?=suffix)

其中"前缀"和"后缀"都是'b,表示单词的开头和结尾。

如果您的禁止单词或短语可能包含特殊字符,则使用 Regex.Escape(word) 来转义它们会更安全。


使用 @zmbq 的想法,您可以创建一次Regex模式

string pattern =
    @"(?<='b)(" +
    String.Join(
        "|",
        bannedWords
            .Select(w => Regex.Escape(w))
            .ToArray()) +
     @")(?='b)";
var regex = new Regex(pattern); // Is compiled by default

然后用

string result = regex.Replace(text, "");

它不起作用,因为您的定义相互冲突。

当您想查找像more than one word这样的子句子时,您不能再在空格上拆分了。你必须依靠String.IndexOf()

如果您追求的是性能,我认为您并不担心一次性设置时间,而是担心连续性能。所以我会构建一个巨大的正则表达式,其中包含所有被禁止的表达式,并确保它被编译 - 这是一个设置。

然后我会尝试将其与文本匹配,并将每个匹配项替换为空白或任何您想要替换的内容。

这样做的原因是,一个大的正则表达式应该编译成类似于你手动创建的有限状态自动机来处理这个问题的东西,所以它应该运行得很好。

为什么不循环访问禁止单词列表并使用方法 string.IndexOf 在字符串中查找每个单词。例如,您可以使用以下代码段删除禁止的单词和短语:

myForbWords.ForEach(delegate(string item) {
    int occ = str.IndexOf(item);
    if(occ > -1) str = str.Remove(occ, item.Length);
});

myForbWords的类型是List<string>