对于我的自定义聊天屏幕,我使用下面的代码来检查删失的字词。但我想知道这个代码性能是否会提高。谢谢。
if (srMessageTemp.IndexOf(" censored1 ") != -1)
return;
if (srMessageTemp.IndexOf(" censored2 ") != -1)
return;
if (srMessageTemp.IndexOf(" censored3 ") != -1)
return;
C#4.0。实际上列表的时间要长得多,但我不会放在这里,因为它消失了。
答案 0 :(得分:4)
我会使用LINQ或正则表达式:
答案 1 :(得分:2)
您可以简化它。这里listOfCencoredWords将包含所有被删除的单词
if (listOfCensoredWords.Any(item => srMessageTemp.Contains(item)))
return;
答案 2 :(得分:2)
如果你想让它真的很快,你可以使用Aho-Corasick自动机。这就是防病毒软件一次检查数千种病毒的方式。但我不知道你可以在哪里完成实现,所以与使用简单的慢速方法(如正则表达式)相比,它需要你做更多的工作。
答案 3 :(得分:1)
首先,我希望你没有真正“书写”所写的字样。你知道,只是因为某人没有在一个坏词之前放置一个空格,它不会使这个词变坏:-)示例,badword,
我会说我会在这里使用正则表达式:-)我不确定正则表达式或人工解析器是否会更快,但至少一个正则表达式将是一个很好的起点。正如其他人写的那样,您首先将文本拆分为单词,然后检查HashSet<string>
。
我正在添加基于ArraySegment<char>
的第二版代码。我稍后会说。
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);
}
}
我会注意到你可以更快地在原始字符串中“解析”。这意味着什么:如果您将“文档”细分为单词并且每个单词都放在string
中,那么显然您正在为文档的每个单词创建一个n
string
。但是,如果您跳过此步骤并直接在文档上操作,只需保留当前索引和当前单词的长度,该怎么办?然后它会更快!显然,您需要为HashSet<>
创建一个特殊的比较器。
但是等等! C#有类似的东西......它被称为ArraySegment。因此,您的文档将是char[]
而不是string
,每个字都是ArraySegment<char>
。显然这要复杂得多!你不能简单地使用Regex
es,你必须“手动”构建一个解析器(但我认为转换\b\w+\b
表达式会很容易)。为HashSet<char>
创建比较器会有点复杂(提示:您将使用HashSet<ArraySegment<char>>
,要审查的字词将ArraySegment
s“指向”char[]
一个单词,大小等于char[].Length
,如var word = new ArraySegment<char>("tobecensored".ToCharArray());
)
在一些简单的基准测试之后,我可以看到使用ArraySegment<string>
的未经优化的程序版本与用于较短文本的Regex
版本一样快。这可能是因为如果一个单词的长度为4-6个字符,则复制它的速度与复制ArraySegment<char>
的速度一样慢(ArraySegment<char>
是12个字节,一个6个字符的单词是12个字节。除了这两个之外,我们还要增加一点开销...但最后数字是可比的)。但是对于较长的文本(尝试退出//sampleText += sampleText;
),它在发布中变得快一点(10%) - &gt;无需调试即启动(CTRL-F5)
我会注意到,逐个字符地比较字符串错误。您应该始终使用string
类(或操作系统)给您的方法。他们知道如何更好地处理“奇怪”案件(在Unicode中没有任何“正常”案例:-))
答案 4 :(得分:0)
您可以使用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());
}
答案 5 :(得分:-1)
您对此有何看法:
string[] censoredWords = new[] { " censored1 ", " censored2 ", " censored3 " };
if (censoredWords.Contains(srMessageTemp))
return;