TheDeveloperBlog.com

Home | Contact Us

CSharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript

C# Char Test With String

This C# performance article shows a fast way to test char values.

String comparisons can be optimized.

We have a constant string in our C# program. We need to test it thousands to billions of times. We benchmark an alternative way of comparing constant strings.

Benchmark

Benchmark of testing chars

StartsWith and EndsWith methods:  2176 ms
Char testing:                      586 ms  [faster]

Methods. In many programs, there are strings that are immutable and will not change throughout the program. I wanted to test request strings in ASP.NET. And I needed to know if the string matched one of two substrings.

Note: The code was critical. It was in the hot path of this application. I optimized several places to manually check characters.

Code that uses EndsWith, A: C#

static bool EndsThreeA(string s)
{
    return s.EndsWith("three", StringComparison.Ordinal);
}

Code that uses char test, B: C#

static bool EndsThreeB(string s)
{
    int len = s.Length;
    if (len >= 5 &&
	s[len - 5] == 't' &&
	s[len - 4] == 'h' &&
	s[len - 3] == 'r' &&
	s[len - 2] == 'e' &&
	s[len - 1] == 'e')
    {
	return true;
    }
    else
    {
	return false;
    }
}

Code that uses StartsWith, A: C#

static bool StartsMsA(string s)
{
    return s.StartsWith("http://microsoft.com", StringComparison.Ordinal) ||
	s.StartsWith("http://msdn.microsoft.com", StringComparison.Ordinal);
}

Code that uses char test, B: C#

static bool StartsMsB(string s)
{
    int len = s.Length;
    if (len > 19 &&
	s[0] == 'h' &&
	s[1] == 't' &&
	s[2] == 't' &&
	s[3] == 'p' &&
	s[4] == ':' &&
	s[5] == '/' &&
	s[6] == '/' &&
	s[7] == 'm')
    {
	if (s[8] == 'i' &&
	    s[9] == 'c' &&
	    s[10] == 'r' &&
	    s[11] == 'o' &&
	    s[12] == 's' &&
	    s[13] == 'o' &&
	    s[14] == 'f' &&
	    s[15] == 't' &&
	    s[16] == '.' &&
	    s[17] == 'c' &&
	    s[18] == 'o' &&
	    s[19] == 'm')
	{
	    return true;
	}
	if (len > 24 &&
	    s[8] == 's' &&
	    s[9] == 'd' &&
	    s[10] == 'n' &&
	    s[11] == '.' &&
	    s[12] == 'm' &&
	    s[13] == 'i' &&
	    s[14] == 'c' &&
	    s[15] == 'r' &&
	    s[16] == 'o' &&
	    s[17] == 's' &&
	    s[18] == 'o' &&
	    s[19] == 'f' &&
	    s[20] == 't' &&
	    s[21] == '.' &&
	    s[22] == 'c' &&
	    s[23] == 'o' &&
	    s[24] == 'm')
	{
	    return true;
	}
	return false;
    }
    return false;
}

Discussion. From a high-level perspective, hard-coding multiple character compares is a poor design. However, the computer doesn't care about code elegance. Logically, the last method shown above does less work that the StartsWith version.

And: If the first check fails, it doesn't repeat itself on the first 8 letters. This can be considered an algorithm improvement.

Benchmark. The "A" methods use StartsWith and EndsWith, and the StringComparison.Ordinal option. The "B" methods individually test chars. We see that the unwound loops, those that test chars individually, are much faster.

StartsWithLoop Unwinding

Summary. We tested individual chars in C# strings for a performance improvement. By testing chars separately, we also avoid redundant work for the computer. This would be an excellent use for a code-generation tool.