To determine if a string is a substring of another string I've used two methods:
- Contains method from the string class:
- IndexOf method from the string class:
Both methods do case-sensitive matching of the strings. However, IndexOf method has an overloaded version which does a case-insensitive matching:
-
Another method to do case-insensitive matching is to use ToLower() method (or ToUpper()) with both strings. Since I needed fast string comparisons I started to wonder if an extra ToLower() method call would cause a huge time penalty.
I decided to compare four methods and variants:
- case-sensitive Contains method:
- case-sensitive IndexOf method:
- case-insensitive IndexOf method with ToLower method:
- case-insensitive
I wrote a small CSharp console application that provides comparisons above and would get accurate enough timing of the comparisons. To get measurable timings each comparison variant was repeated in a loop.
So here is the code:
class Program
{
public static string stringToSearch;
public static string text = "A Function to search for";
public static bool match = false;
public static DateTime startTime;
public static TimeSpan elapsedTime;
public static int Method1(int loops, string stringToSearch)
{
startTime = DateTime.Now;
for(int i = 0; i < loops; i++)
{
match = text.Contains(stringToSearch);
}
elapsedTime = DateTime.Now.Subtract(startTime);
Console.WriteLine("Contains(" + stringToSearch + "): " + match.ToString());
Console.WriteLine("Elapsed: " + (int)elapsedTime.TotalMilliseconds);
return (int)elapsedTime.TotalMilliseconds;
}
public static int Method2(int loops, string stringToSearch)
{
startTime = DateTime.Now;
for (int i = 0; i < loops; i++)
{
match = text.IndexOf(stringToSearch) >= 0;
}
elapsedTime = DateTime.Now.Subtract(startTime);
Console.WriteLine("IndexOf(" + stringToSearch + "): " + match.ToString());
Console.WriteLine("Elapsed: " + (int)elapsedTime.TotalMilliseconds);
return (int)elapsedTime.TotalMilliseconds;
}
public static int Method3(int loops, string stringToSearch)
{
startTime = DateTime.Now;
for (int i = 0; i < loops; i++)
{
match = text.ToLower().IndexOf(stringToSearch.ToLower()) >= 0;
}
elapsedTime = DateTime.Now.Subtract(startTime);
Console.WriteLine("IndexOf(" + stringToSearch + ".ToLower()): " + match.ToString());
Console.WriteLine("Elapsed: " + (int)elapsedTime.TotalMilliseconds);
return (int)elapsedTime.TotalMilliseconds;
}
public static int Method4(int loops, string stringToSearch)
{
startTime = DateTime.Now;
for (int i = 0; i < loops; i++)
{
match = text.IndexOf(stringToSearch, 0, StringComparison.OrdinalIgnoreCase) >= 0;
}
elapsedTime = DateTime.Now.Subtract(startTime);
Console.WriteLine("IndexOf(" + stringToSearch + ", 0, StringComparison.OrdinalIgnoreCase) :" + match.ToString());
Console.WriteLine("Elapsed: " + (int)elapsedTime.TotalMilliseconds);
return (int)elapsedTime.TotalMilliseconds;
}
static void Main(string[] args)
{
int loops = 1000000; // One million
int m1 = 0;
int m2 = 0;
int m3 = 0;
int m4 = 0;
stringToSearch = "Function";
m1 += Method1(loops, stringToSearch);
m2 += Method2(loops, stringToSearch);
m3 += Method3(loops, stringToSearch);
m4 += Method4(loops, stringToSearch);
Console.WriteLine();
stringToSearch = "not found";
m1 += Method1(loops, stringToSearch);
m2 += Method2(loops, stringToSearch);
m3 += Method3(loops, stringToSearch);
m4 += Method4(loops, stringToSearch);
Console.WriteLine();
Console.WriteLine("Method 1 Elapsed: " + (int)(m1 / 2));
Console.WriteLine("Method 2 Elapsed: " + (int)(m2 / 2));
Console.WriteLine("Method 3 Elapsed: " + (int)(m3 / 2));
Console.WriteLine("Method 4 Elapsed: " + (int)(m4 / 2));
Console.ReadKey();
}
}
The code itself is pretty simple and should be self- explanatory.
Each method was executed both with a string that would be found and with a string that would not be found. The final timing was the average of these two.
For the case-insensitive searching
No comments:
Post a Comment