Splitting Pascal/Camel Cased Strings

Found this post in RossCode which mentions a blog post that discusses how to bind enumerations to drop downs, something I’ve done quite often.

RossCode has an issue with using this approach personally because typically, the display text of a drop down should have spaces between words, which is not allowed in an enum value. For example...

public enum UglinessFactor

{

    ButtUgly,

    Fugly,

    NotSoBad,

}

In the preceding enumeration, you’d probably want the dropdown to display “Butt Ugly” and not “ButtUgly”.

Well if you follow standard .NET naming conventions and Pascal Case your enum values, the following method SplitUpperCaseToString may be of service. It depends on another method SplitUpperCase which will split a camel or pascal cased word into an array of component words.

As a refresher, a Pascal Cased string is one in which the first letter of each word is capitalized. For example, ThisIsPascalCased. By contrast, a Camel Cased string is one in which the first letter of the string is lowercase, but the first letter of each successive word is upper cased. For example, thisIsCamelCased.

Try it out and let me know if it was useful for you.

/// <summary>

/// Parses a camel cased or pascal cased string and returns a new

/// string with spaces between the words in the string.

/// </summary>

/// <example>

/// The string "PascalCasing" will return an array with two

/// elements, "Pascal" and "Casing".

/// </example>

/// <param name="source"></param>

/// <returns></returns>

public static string SplitUpperCaseToString(string source)

{

    return string.Join(" ", SplitUpperCase(source));

}

 

/// <summary>

/// Parses a camel cased or pascal cased string and returns an array

/// of the words within the string.

/// </summary>

/// <example>

/// The string "PascalCasing" will return an array with two

/// elements, "Pascal" and "Casing".

/// </example>

/// <param name="source"></param>

/// <returns></returns>

public static string[] SplitUpperCase(string source)

{

    if(source == null)

        return new string[] {}; //Return empty array.

 

    if(source.Length == 0)

        return new string[] {""};

 

    StringCollection words = new StringCollection();

    int wordStartIndex = 0;

 

    char[] letters = source.ToCharArray();

    // Skip the first letter. we don't care what case it is.

    for(int i = 1; i < letters.Length; i++)

    {

        if(char.IsUpper(letters[i]))

        {

            //Grab everything before the current index.

            words.Add(new String(letters, wordStartIndex, i - wordStartIndex));

            wordStartIndex = i;

        }

    }

    //We need to have the last word.

    words.Add(new String(letters, wordStartIndex, letters.Length - wordStartIndex));

 

    //Copy to a string array.

    string[] wordArray = new string[words.Count];

    words.CopyTo(wordArray, 0);

    return wordArray;

}

[ad] Free Bug Tracking & Project Management Software Axosoft’s OnTime 2007 allows software development teams to collaborate on software projects by tracking everything from defects to enhancements to helpdesk incidents in one easy-to-use database driven by an intuitive Windows, Web or VS.NET Integrated UI. Get a Free Single-User License ($200 Value!)

What others have said

Requesting Gravatar... Joel Ross Sep 24, 2005 11:56 AM
# re: Splitting Pascal/Camel Cased Strings
Phil,

Thanks for the feedback and advice. This is a great idea, and since I do follow that naming convention, this would definitely work. I'm not sure why it never occured to me!

And, how'd you know what enumeration I wanted to bind to? ;-)
Requesting Gravatar... Haacked Sep 24, 2005 12:22 PM
# re: Splitting Pascal/Camel Cased Strings
Everybody wants to bind the UglinessFactor enumeration. It is probably the most used enumeration in the framework.
Requesting Gravatar... Kevin Dente Sep 24, 2005 3:18 PM
# re: Splitting Pascal/Camel Cased Strings
Err...not a very localizable solution. Perhaps that's not an issue for them, but I would hestitate to recommend this as a general solution. Cool for quick-and-dirty stuff though. ;)
Requesting Gravatar... Chris Martin Sep 24, 2005 4:34 PM
# re: Splitting Pascal/Camel Cased Strings
I've never thought about doing it that way. Something about it smells funny though. It's not very .NETish. This is what I end up doing when binding to enums.


public enum UglinessFactor
{
[EnumDisplayText("Butt Ugly")]
ButtUgly,

[EnumDisplayText("Freakin Ugly")]
Fugly,

[EnumDisplayText("Not So Bad")]
NotSoBad,
}

public class EnumDisplayTextAttribute : Attribute
{
private Enum _host;
private string _text;

public EnumDisplayTextAttribute (string text)
{
this._text = text;
}

public static EnumDisplayTextAttribute Parse(Enum value)
{
EnumDisplayTextAttribute toReturn = null;

Type type = value.GetType();

FieldInfo field = type.GetField(value.ToString());

object[] attributes = field.GetCustomAttributes(typeof(EnumDisplayTextAttribute), false);

if(attributes.Length > 0)
{
toReturn = (EnumDisplayTextAttribute)attributes[0];
toReturn._host = value;
}

return toReturn;
}

public Enum Host
{
get { return _host; }
}

public string Text
{
get { return _text; }
}
}

public class Application
{
private static void Main()
{
string[] names = Enum.GetNames(typeof(UglinessFactor));

foreach(string name in names)
{
UglinessFactor uglyFactor = (UglinessFactor)Enum.Parse(typeof(UglinessFactor), name, true);

EnumDisplayTextAttribute attribute = EnumDisplayTextAttribute.Parse(uglyFactor);

Console.WriteLine("Host Enum: {0}\nDisplayText: {1}\n", attribute.Host.ToString(), attribute.Text);
}

Console.ReadLine();
}
}
Requesting Gravatar... Haacked Sep 24, 2005 5:29 PM
# re: Splitting Pascal/Camel Cased Strings
Chris, your solution is definitely a better approach if you have control over the enum. But if you were doing a bind to an enum for a library, you might not have the benefit of adding attributes to it.

Kevin, I assume you mean binding to the enum is not a localizable solution. Yes, I agree, that isn&#8217;t localizable. A localizable solution would be to use the enum value as a key into a resource file and not fiddle around with my method at all.

But if you were binding an array of enums values that are culture invariant, say an enum of proper names, then this could work.
Requesting Gravatar... Jon Galloway Sep 24, 2005 10:33 PM
# re: Splitting Pascal/Camel Cased Strings
You can do this with a regex replace, too: (?<=[a-z])(?=[A-Z])

Here's a post about PHP code snip that uses it. A lot less code and I'd bet it's faster:

http://ad.hominem.org/log/2004/12/camelcase.php
Requesting Gravatar... Haacked Sep 25, 2005 9:04 PM
# re: Splitting Pascal/Camel Cased Strings
I'm not so sure it's going to be faster. At least, if we compare the methods that split camel case into an array (not the one that joins it back).

Consider that char by char parsing is almost always faster than a generalized regex engine.

Also consider that the use case for this method will on average at most split something into three words.

But of course, I'd like to see some measurements. Measure, measure, measure.
Requesting Gravatar... Joel Ross Sep 25, 2005 9:37 PM
# Binding To An Enumeration - A Followup
Requesting Gravatar... secretGeek Sep 28, 2005 8:44 PM
# re: Splitting Pascal/Camel Cased Strings
Hey boss

I've fixed this problem in the past through use of a function called 'DisPascalize' (i've blogged about it here
http://secretgeek.net/progr_purga.asp)

it relies on regular expression. initially i thought this was a criminally bad solution -- but a year and a half later and i still use it!

cheers
lb

What do you have to say?

(will show your gravatar)
Please add 7 and 7 and type the answer here: