views:

2006

answers:

9

How do I go from this string: "ThisIsMyCapsDelimitedString"

...to this string: "This Is My Caps Delimited String"

Fewest lines of code in VB.net is preferred but C# is also welcome.

Cheers!

A: 

There's probably a more elegant solution, but this is what I come up with off the top of my head:

string myString = "ThisIsMyCapsDelimitedString";

for (int i = 1; i < myString.Length; i++)
{
     if (myString[i].ToString().ToUpper() == myString[i].ToString())
     {
          myString = myString.Insert(i, " ");
          i++;
     }
}
Max Schmeling
+7  A: 

Grant Wagner's excellent comment aside:

Dim s As String = RegularExpressions.Regex.Replace("ThisIsMyCapsDelimitedString", "([A-Z])", " $1")
Pseudo Masochist
This leaves the result with a leading space: " This Is M...
Ferruccio
Good point... Please feel free to insert the .substring(), .trimstart(), .trim(), .remove(), etc. of your choice. :)
Pseudo Masochist
+3  A: 
string s = "ThisIsMyCapsDelimitedString";
string t = Regex.Replace(s, "([A-Z])", " $1").Substring(1);
Ferruccio
I knew there would be an easy RegEx way... I've got to start using it more.
Max Schmeling
Not a regex guru but what happens with "HeresAWTFString"?
Nick
You get "Heres A W T F String" but that's exactly what Matias Nino asked for in the question.
Max Schmeling
+9  A: 
Regex.Replace("ThisIsMyCapsDelimitedString", "(\\B[A-Z])", " $1")
Wayne
This is the best solution so far, but you need to use \\B to compile. Otherwise the compiler tries to treat the \B as an escape sequence.
Ferruccio
Nice solution. Can anyone think of a reason that this shouldn't be the accepted answer? Is it less capable or less performant?
Drew Noakes
+1  A: 

Naive regex solution. Will not handle O'Conner, and adds a space at the start of the string as well.

s = "ThisIsMyCapsDelimitedString"
split = Regex.Replace(s, "[A-Z0-9]", " $&");
Geoff
I modded you up, but people generally take a smackdown better if it doesn't start with "naive".
MusiGenesis
I don't think that was a smackdown. In this context, naive usually means obvious or simple (i.e. not necessarily the best solution). There is no intention of insult.
Ferruccio
Yeah i meant simplistic
Geoff
+5  A: 

Just for a little variety... Here's an extension method that doesn't use a regex.

public static class CamelSpaceExtensions
{
    public static string SpaceCamelCase(this String input)
    {
        return new string(InsertSpacesBeforeCaps(input).ToArray());
    }

    private static IEnumerable<char> InsertSpacesBeforeCaps(IEnumerable<char> input)
    {
        foreach (char c in input)
        {
            if (char.IsUpper(c)) 
            { 
                yield return ' '; 
            }

            yield return c;
        }
    }
}
Troy Howard
+31  A: 

I made this a while ago. It matches each component of a CamelCase name.

/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g

For example:

"SimpleHTTPServer" => ["Simple", "HTTP", "Server"]
"camelCase" => ["camel", "Case"]

To convert that to just insert spaces between the words:

Regex.Replace(s, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ")

Edit: Allowing initial lowercase letters, (i.e. "lowerCamelCase"), as Drew Noakes pointed out. The only change is a "?" after after the last "[A-Z]".

MizardX
CamelCase! That's what it was called! I love it!Thanks much!
Matias Nino
Actually camelCase has a leading lowercase letter. What you're referring to here is PascalCase.
Drew Noakes
This has been corrected.
MizardX
...and when you refer to something that can be "camel case" or "pascal case" it is called "intercapped"
Chris
+1  A: 

For more variety, using plain old C# objects, the following produces the same output as @MizardX's excellent regular expression.

public string FromCamelCase(string camel)
{   // omitted checking camel for null
    StringBuilder sb = new StringBuilder();
    int upperCaseRun = 0;
    foreach (char c in camel)
    {   // append a space only if we're not at the start
        // and we're not already in an all caps string.
        if (char.IsUpper(c))
        {
            if (upperCaseRun == 0 && sb.Length != 0)
            {
                sb.Append(' ');
            }
            upperCaseRun++;
        }
        else if( char.IsLower(c) )
        {
            if (upperCaseRun > 1) //The first new word will also be capitalized.
            {
                sb.Insert(sb.Length - 1, ' ');
            }
            upperCaseRun = 0;
        }
        else
        {
            upperCaseRun = 0;
        }
        sb.Append(c);
    }

    return sb.ToString();
}
Robert Paulson
Wow, that's ugly. Now I remember why I so dearly love regex! +1 for effort, though. ;)
Mark Brackett
lol .. totally ugly. regex is the way to go!
Robert Paulson
A: 

Great answer, MizardX! I tweaked it slightly to treat numerals as separate words, so that "AddressLine1" would become "Address Line 1" instead of "Address Line1":

Regex.Replace(s, "([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 ")
JoshL