Here comes another great string extension for improved readability. You all know how to check if a string starts with another string (yep, it's the StartsWith method I'm talking about).
But what if you wan't to check if a string starts with any of a series of strings? Well, you'd have to do something like this.
string name = "Mr. Markus Olsson"
var l = new List<string> { "Dr", "Mr", "Ms" };
bool found;
foreach(string s in l) {
if(name.StartsWith(l)) {
found = true;
break;
}
}
Or, you could use lambdas for a much more elegant solution
string name = "Mr. Markus Olsson"
var l = new List<string> { "Dr", "Mr", "Ms" };
bool found = l.Exists(prefix => name.StartsWith(prefix));
That's pretty cool, right? The .Exists method on the list object takes a Predicate
Enter StartsWithAnyOf extension methods
/// <summary>
/// Checks to see if the string starts with any of the supplied strings
/// </summary>
/// <param name="s">The string to check for a start value</param>
/// <param name="strings">One or more strings</param>
/// <returns>True the strings starts with any of the supplied strings, false otherwise</returns>
public static bool StartsWithAnyOf(this string s, params string[] strings)
{
if (s == null)
throw new ArgumentNullException("s");
if (strings == null)
throw new ArgumentNullException("strings");
if (strings.Length == 0)
throw new ArgumentOutOfRangeException("strings", "You must supply one or more strings");
return Array.Exists(strings, (prefix => s.StartsWith(prefix));
}
/// <summary>
/// Checks to see if the string starts with any of the supplied strings
/// </summary>
/// <param name="s">The string to check for a start value</param>
/// <param name="strings">One or more strings</param>
/// <returns>True the strings starts with any of the supplied strings, false otherwise</returns>
public static bool StartsWithAnyOf(this string s, List<string> strings)
{
if (s == null)
throw new ArgumentNullException("s");
if (strings == null)
throw new ArgumentNullException("strings");
if (strings.Count == 0)
throw new ArgumentOutOfRangeException("strings", "You must supply one or more strings");
return strings.Exists(x => s.StartsWith(x));
}
This allows us to rewrite our code to
string name = "Mr. Markus Olsson"
bool found = name.StartsWithAnyOf("Dr.", "Mr.", "Ms.");
Readability in a nutshell. Variations of these extension methods includes an override that takes a StringComparison in order to allow for case insensitive lookup. The EndsWithAnyOf method is of course also a must.
5 comments:
Hejhej, now im not even a csharp newbie, but my eyes sees some code duplication :) could the first method that takes an array of strings just use the second metohd?
Pseudo-c-sharp:
public static bool StartsWithAnyOf(this string s, params string[] strings)
{
return s.StartWithAnyOf(strings.ToList())
}
Spot on! Actually the original post didn't contain the duplication and used the second method as you suggest but I changed it at the last minute due to the fact that when you use the "params string[]" method you probably aren't going to be sending in more than a few strings, like this:
s.StartsWithAnyOf("foo", "bar");
So I just thought that the overhead of creating a new list and then creating an enumerator for looping through the strings in the list was a bit too much but I really do agree with you and I have as a matter of fact implemented it using the "code dup" way in our core library at work.
Nice catch though, didn't think anyone would notice ;)
Actually, the way you really want it is:
public static bool StartsWithAnyOf(this string s, params string[] strings)
{
// parameter checking
return Array.Exists(strings, (prefix => s.StartsWith(prefix));
}
Right you are James! I actually didn't know that method existed. It makes perfect sense that it would though. I've updated the post.
Thanks!
To be sure, what you really want is
l.Exists(p => name.StartsWith(p));
Littering your code with extension methods like StartsWithAnyOf will probably prove to be detrimental to readability.
Faced with (new) code, seeing
mylocalvar.StartsWithAnyOf(list);
I'd have to step into that extension method to make sure it does what it says (even if it's my own 6-months old code).
If I instead see:
l.Exists(p => name.StartsWith(p));
I'll know exactly what it does. Thats readability!
Post a Comment