Showing posts with label string extensions. Show all posts
Showing posts with label string extensions. Show all posts

September 12, 2008

ToTitleCase

Not to long ago I had to write a method to convert lowercase names to proper case for display on a website I was working on. I started rolling my own but then I thought that such a feature would be nice to have in the framework. So I hit google with a query and sure enough the framework authors had thought of it. The method was well hidden though ;)

CultureInfo.InvariantCulture.TextInfo.ToTitleCase("hELLo wORLd");
// Will return "Hello World"

This fits quite well in as an extension method

/// <summary>
/// Creates a new string with Title Case (ie "hEllO wORLd" becomes  "Hello World") using the Invariant Culture
/// </summary>
/// <param name="s">The string to convert</param>
/// <returns>The string in title case</returns>
public static string ToTitleCaseInvariant(this string s)
{
    return ToTitleCase(s, CultureInfo.InvariantCulture);
}

/// <summary>
/// Creates a new string with Title Case (ie "hEllO wORLd" becomes  "Hello World")
/// </summary>
/// <param name="s">The string to convert</param>
/// <returns>The string in title case</returns>
public static string ToTitleCase(this string s)
{
    return ToTitleCase(s, CultureInfo.CurrentCulture);
}

/// <summary>
/// Creates a new string with Title Case (ie "hEllO wORLd" becomes  "Hello World")
/// </summary>
/// <param name="s">The string to convert</param>
/// <param name="ci">The culture to use when creating title case</param>
/// <returns>The string in title case</returns>
public static string ToTitleCase(this string s, CultureInfo ci)
{
    if (s == null)
        throw new ArgumentNullException("s");

    return ci.TextInfo.ToTitleCase(s);
}

Now you can just call the ToTitleCase on your string objects like this:

var s = "george washington";
s.ToTitleCase();
kick it on DotNetKicks.com

Licensing information

August 31, 2008

StartsWithAnyOf extension method

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 as a parameter and executes that predicate with each element as it's first argument until it finds a match. Coolio indeed but we can do better readability wise.

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.

Update: as mattias pointed out there's a bit of code duplication here but that's intentional, read why
Update 2: I changed my mind again after discussing it with mattias and for the sake of readability and code-duplication I've decided to wrap the first method into a call of the second.
Update 3: James Curran pointed out that the Array class have an Exist method and that's of course what you want for the string array. Thanks James!

Licensing information

kick it on DotNetKicks.com