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会更快?哪一个?这不会将其自身局限于单词边界,它会重新搜索消息字符串中的每个单词。