C# 最佳文字审查方法-C4.0
对于我定制的聊天屏幕,我使用下面的代码检查被删单词。但我想知道这段代码的性能能否得到提高。多谢各位C# 最佳文字审查方法-C4.0,c#,keyword,C#,Keyword,对于我定制的聊天屏幕,我使用下面的代码检查被删单词。但我想知道这段代码的性能能否得到提高。多谢各位 if (srMessageTemp.IndexOf(" censored1 ") != -1) return; if (srMessageTemp.IndexOf(" censored2 ") != -1) return; if (srMessageTemp.IndexOf(" censored3 ") != -1) retu
if (srMessageTemp.IndexOf(" censored1 ") != -1)
return;
if (srMessageTemp.IndexOf(" censored2 ") != -1)
return;
if (srMessageTemp.IndexOf(" censored3 ") != -1)
return;
C4.0。实际上,这个列表要长得多,但随着它的消失,我不会把它放在这里。我会使用LINQ或正则表达式来实现这一点: 林克: 正则表达式:
您对此有何看法:
string[] censoredWords = new[] { " censored1 ", " censored2 ", " censored3 " };
if (censoredWords.Contains(srMessageTemp))
return;
你可以简化它。在这里,编码词列表将包含所有经过审查的词
if (listOfCensoredWords.Any(item => srMessageTemp.Contains(item)))
return;
如果你想让它变得非常快,你可以使用一个自动机器。这就是防病毒软件一次检查数千个病毒的方式。但我不知道在哪里可以完成实现,因此与使用简单的、缓慢的方法(如正则表达式)相比,它需要您做更多的工作
请参见此处的理论:您可以使用linq来实现此目的,但如果您使用列表来保存经过审查的值列表,则不需要使用linq。下面的解决方案使用内置列表函数,允许您执行不区分大小写的搜索
private static List<string> _censoredWords = new List<string>()
{
"badwordone1",
"badwordone2",
"badwordone3",
"badwordone4",
};
static void Main(string[] args)
{
string badword1 = "BadWordOne2";
bool censored = ShouldCensorWord(badword1);
}
private static bool ShouldCensorWord(string word)
{
return _censoredWords.Contains(word.ToLower());
}
首先,我希望你不是真的像写的那样标记单词。你知道,仅仅因为某人没有在一个坏词前加空格,这并不能使这个词不那么坏:-例如,坏词 我会说我会在这里使用正则表达式:-我不确定正则表达式或人造解析器是否会更快,但至少正则表达式是一个很好的起点。正如其他人所写,您首先将文本拆分为单词,然后检查哈希集 我正在添加第二个版本的代码,基于ArraySegment。我稍后再谈这件事
class Program
{
class ArraySegmentComparer : IEqualityComparer<ArraySegment<char>>
{
public bool Equals(ArraySegment<char> x, ArraySegment<char> y)
{
if (x.Count != y.Count)
{
return false;
}
int end = x.Offset + x.Count;
for (int i = x.Offset, j = y.Offset; i < end; i++, j++)
{
if (!x.Array[i].ToString().Equals(y.Array[j].ToString(), StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
}
return true;
}
public override int GetHashCode(ArraySegment<char> obj)
{
unchecked
{
int hash = 17;
int end = obj.Offset + obj.Count;
int i;
for (i = obj.Offset; i < end; i++)
{
hash *= 23;
hash += Char.ToUpperInvariant(obj.Array[i]);
}
return hash;
}
}
}
static void Main()
{
var rx = new Regex(@"\b\w+\b", RegexOptions.Compiled);
var sampleText = @"For my custom made chat screen i am using the code below for checking censored words. But i wonder can this code performance improved. Thank you.
if (srMessageTemp.IndexOf("" censored1 "") != -1)
return;
if (srMessageTemp.IndexOf("" censored2 "") != -1)
return;
if (srMessageTemp.IndexOf("" censored3 "") != -1)
return;
C# 4.0 . actually list is a lot more long but i don't put here as it goes away.
And now some accented letters àèéìòù and now some letters with unicode combinable diacritics àèéìòù";
//sampleText += sampleText;
//sampleText += sampleText;
//sampleText += sampleText;
//sampleText += sampleText;
//sampleText += sampleText;
//sampleText += sampleText;
//sampleText += sampleText;
HashSet<string> prohibitedWords = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) { "For", "custom", "combinable", "away" };
Stopwatch sw1 = Stopwatch.StartNew();
var words = rx.Matches(sampleText);
foreach (Match word in words)
{
string str = word.Value;
if (prohibitedWords.Contains(str))
{
Console.Write(str);
Console.Write(" ");
}
else
{
//Console.WriteLine(word);
}
}
sw1.Stop();
Console.WriteLine();
Console.WriteLine();
HashSet<ArraySegment<char>> prohibitedWords2 = new HashSet<ArraySegment<char>>(
prohibitedWords.Select(p => new ArraySegment<char>(p.ToCharArray())),
new ArraySegmentComparer());
var sampleText2 = sampleText.ToCharArray();
Stopwatch sw2 = Stopwatch.StartNew();
int startWord = -1;
for (int i = 0; i < sampleText2.Length; i++)
{
if (Char.IsLetter(sampleText2[i]) || Char.IsDigit(sampleText2[i]))
{
if (startWord == -1)
{
startWord = i;
}
}
else
{
if (startWord != -1)
{
int length = i - startWord;
if (length != 0)
{
var wordSegment = new ArraySegment<char>(sampleText2, startWord, length);
if (prohibitedWords2.Contains(wordSegment))
{
Console.Write(sampleText2, startWord, length);
Console.Write(" ");
}
else
{
//Console.WriteLine(sampleText2, startWord, length);
}
}
startWord = -1;
}
}
}
if (startWord != -1)
{
int length = sampleText2.Length - startWord;
if (length != 0)
{
var wordSegment = new ArraySegment<char>(sampleText2, startWord, length);
if (prohibitedWords2.Contains(wordSegment))
{
Console.Write(sampleText2, startWord, length);
Console.Write(" ");
}
else
{
//Console.WriteLine(sampleText2, startWord, length);
}
}
}
sw2.Stop();
Console.WriteLine();
Console.WriteLine();
Console.WriteLine(sw1.ElapsedTicks);
Console.WriteLine(sw2.ElapsedTicks);
}
}
我会注意到,在原始字符串中进行解析可以更快。这意味着什么:如果您将文档细分为单词,并且每个单词都放在一个字符串中,那么显然您正在创建n个字符串,文档中的每个单词对应一个字符串。但是如果跳过这一步,直接对文档进行操作,只保留当前索引和当前单词的长度,会怎么样?那就快了!显然,您需要为HashSet创建一个特殊的比较器
但是等等!C有类似的东西。。。它叫。因此,您的文档将是一个char[]而不是一个字符串,并且每个单词都将是一个ArraySegment。显然,这要复杂得多!您不能简单地使用正则表达式,您必须手动构建解析器,但我认为转换\b\w+\b表达式将非常容易。为HashSet创建一个比较器会有一点复杂的提示:使用HashSet,要检查的单词将是ArraySegments,指向单词的char[],大小等于char[].Length,比如var word=new arraysegmenttobesensored.ToCharArray
在一些简单的基准测试之后,我可以看到使用ArraySegment的程序的未优化版本与用于较短文本的正则表达式版本一样快。这可能是因为如果一个单词的长度为4-6个字符,那么复制它的速度与复制ArraySegment的速度一样慢。ArraySegment是12字节,6个字符的单词是12字节。除此之外,我们还需要增加一些开销。。。但最终这些数字是可比的。但对于较长的文本,请尝试取消//sampleText+=sampleText;在Release->Start中,无需调试CTRL-F5,速度会加快10%
我会注意到逐个字符比较字符串是错误的。您应该始终使用string类或OS提供给您的方法。他们比你更了解如何处理奇怪的情况,在Unicode中没有任何正常情况:-当你找到这些单词时,你会怎么做?顺便说一句,使用带有单词边界的正则表达式更准确,因为你的方法找不到蔓越莓。如果您想替换单词,这可能会有所帮助:。美式英语可以alw@ys这是非常正确的,但至少这有帮助:chibacity,我要看看。你好。这似乎是一个非常体面的解决方案。这会更快吗?这行不通。我们正在检查用户输入的句子是否包含任何不好的单词。如果是这样的话,那么您只需使用该句子-使用string.Split方法创建一个字符串数组-并将每个字符串传递给ShouldCensorWord方法……。您对这一点有很好的理解。是的,在检查之前,我正在替换这些字符。你的解释真令人困惑。我想要的就是获得最佳性能。gyurisc建议linq。你认为这是最好的吗?我当然可以把这个句子分成几个字。但是检查每一个被审查的单词会更快吗?我还可以创建一组字符串。但是这会更快吗?@MonsterMMORPG如果你正在替换字符,那么如果你只想提高速度,那么你可能已经做错了。@MonsterMMORPG更新了代码。对于小文本,使用ArraySegment的速度与直接使用正则表达式的速度相同,但编写起来要复杂得多。对于较大的文本,它的速度要快10%。@MonsterMMORPG如果你正在替换字符,那么你是专业的
如果你只想要速度的话,bably已经做错了。这是因为操纵一大块文本是一件很慢的事情。我希望您在文本前加一个空格,在文本后加一个空格,否则srMessageTemp.IndexOf censored1将与censored1不匹配。谢谢您的回答。但我想问这个。制作一个单词的字符串数组。给定的句子最多140个字符。然后,在循环中检查数组是否包含任何已删失的内容会更快,或者使用linq会更快?哪一个?这不会将其自身局限于单词边界,它会重新搜索消息字符串中的每个单词。