快速确保字符串不包含特定字符的方法

时间:2013-12-18 11:20:15

标签: c# string performance validation

我想确保C#字符串不包含特定字符。

我正在使用string.IndexOfAny(char[]),在我看来,Regex在此任务中会更慢。有没有更好的方法来实现这一目标?速度在我的应用中至关重要。

4 个答案:

答案 0 :(得分:4)

快速对IndexOf vs IndexOfAny vs Regex vs Hashset进行基准测试。
500字lorem ipsum干草堆,有两个字符针。
在大海捞针处测试,一个在大海捞针中,不在大海捞针中。

    private long TestIndexOf(string haystack, char[] needles)
    {
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            int x = haystack.IndexOfAny(needles);
        }
        sw.Stop();

        return sw.ElapsedMilliseconds;
    }

    private long TestRegex(string haystack, char[] needles)
    {
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        Regex regex = new Regex(string.Join("|", needles));
        for (int i = 0; i < 1000000; i++)
        {
            Match m = regex.Match(haystack);
        }
        sw.Stop();

        return sw.ElapsedMilliseconds;
    }

    private long TestIndexOf(string haystack, char[] needles)
    {
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            int x = haystack.IndexOf(needles[0]);
        }
        sw.Stop();

        return sw.ElapsedMilliseconds;
    }

    private long TestHashset(string haystack, char[] needles)
    {
        HashSet<char> specificChars = new HashSet<char>(needles.ToList());
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            bool notContainsSpecificChars = !haystack.Any(specificChars.Contains);
        }
        sw.Stop();

        return sw.ElapsedMilliseconds;
    }

1,000,000次迭代的结果:

  

索引:28/2718/2711
  任意指数:153/141/17561
  正则表达式:1068/1102/92324
  Hashset:939/891/111702

注意:

  • 较小的草堆可以提高性能。
  • 较大的针头组可提高正则表达能力。
  • 较大的针头组可降低其性能指标。
  • 如果针头不在大海捞针中,则所有方法的性能都会下降

总体而言,regexindexofany慢了10倍,具体取决于干草堆和针头尺寸。

答案 1 :(得分:2)

您可以使用这种简洁有效的LINQ查询:

HashSet<char> specificChars = new HashSet<char>{ 'a', 'b', 'c'};
bool notContainsSpecificChars = !"test".Any(specificChars.Contains); // true

我使用了HashSet<char>,因为它对查找有效,不允许重复。

如果你有一个数组作为输入,你可以使用constructor从中创建一个HashSet

char[] chars = new[] { 'a', 'b', 'c', 'c' };
specificChars = new HashSet<char>(chars); // c is removed since it was a duplicate

没有HashSet的另一种方法是使用Enumerable.Intersect + Enumerable.Any

bool notContainsSpecificChars = !"test".Intersect(chars).Any();

答案 2 :(得分:0)

如果你必须只找到一个字符,那么最好调用方法IndexOf(singleChar)或IndexOf(singleChar,startIndex,charCount)。

诅咒正则表达式会更加昂贵!

答案 3 :(得分:0)

String.IndexOfAny(char[])在CLR中实现,String.IndexOf使用extern调用,所以它们都非常快。要么比使用正则表达式要快得多。

IndexOf是否优于IndexOfAny取决于您期望检查的字符数。基于一些非常粗略的基准测试,看起来IndexOf对于2个或更少的字符表现得更好(少量),但IndexOfAny对3个或更多的表现更好。但差别很小 - 使用IndexOfAny的优势可能会被分配字符数组的成本所淹没。