我有一个包含禁用单词的字符串列表。检查字符串是否包含任何禁用单词并将其从字符串中删除的有效方法是什么?目前,我有这个:
cleaned = String.Join(" ", str.Split().Where(b => !bannedWords.Contains(b,
StringComparer.OrdinalIgnoreCase)).ToArray());
这适用于单个禁用单词,但不适用于短语(例如
more than one word
)。任何 more than one word
的实例也应该被删除。我想到尝试的另一种方法是使用 List 的 Contains 方法,但它只返回 bool 而不是匹配单词的索引。如果我可以获得匹配单词的索引,我可以使用 String.Replace(bannedWords[i],"");
简单的
String.Replace
不起作用,因为它会删除单词部分。如果“sex”是禁用词,而您有“sextet”这个词,但该词未被禁用,您应该保持原样。
使用
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", "")
}
\b
代表单词开头和结尾。我首先有一个使用正则表达式前瞻和后瞻的解决方案;然而,这对于 \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>
。