How do I convert PascalCase to kebab-case with C#?
Asked Answered
E

8

28

How do I convert a string value in PascalCase (other name is UpperCamelCase) to kebab-case with C#?

e.g. "VeryLongName" to "very-long-name"

Elwandaelwee answered 18/5, 2016 at 13:35 Comment(0)
E
44

Here is how to do that with a regular expression:

public static class StringExtensions
{
    public static string PascalToKebabCase(this string value)
    {
        if (string.IsNullOrEmpty(value))
            return value;

        return Regex.Replace(
            value,
            "(?<!^)([A-Z][a-z]|(?<=[a-z])[A-Z0-9])",
            "-$1",
            RegexOptions.Compiled)
            .Trim()
            .ToLower();
    }
}

Note: the @RossK92's recommendation about handling numbers has been applied

Elwandaelwee answered 18/5, 2016 at 13:38 Comment(2)
this does not seem to handle numbers well. In my case the word "CdWindows2016" is converted to cd-windows2016. I would have expected cd-windows-2016. According to textedit.tools/kebabcase it converts the way I expected.Louisiana
replace the pattern with the following to handle numbers: "(?<!^)([A-Z][a-z]|(?<=[a-z])[A-Z0-9])"Cheffetz
R
21

Here's my solution using Microsoft's capitalization conventions. https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions

public static class StringExtensions
{
    public static string PascalToKebabCase(this string source)
    {
        if (source is null) return null;

        if (source.Length == 0) return string.Empty;

        StringBuilder builder = new StringBuilder();

        for (var i = 0; i < source.Length; i++)
        {
            if (char.IsLower(source[i])) // if current char is already lowercase
            {
                builder.Append(source[i]);
            }
            else if (i == 0) // if current char is the first char
            {
                builder.Append(char.ToLower(source[i]));
            }
            else if (char.IsDigit(source[i]) && !char.IsDigit(source[i - 1])) // if current char is a number and the previous is not
            {
                builder.Append('-');
                builder.Append(source[i]);
            }
            else if (char.IsDigit(source[i])) // if current char is a number and previous is
            {
                builder.Append(source[i]);
            }
            else if (char.IsLower(source[i - 1])) // if current char is upper and previous char is lower
            {
                builder.Append('-');
                builder.Append(char.ToLower(source[i]));
            }
            else if (i + 1 == source.Length || char.IsUpper(source[i + 1])) // if current char is upper and next char doesn't exist or is upper
            {
                builder.Append(char.ToLower(source[i]));
            }
            else // if current char is upper and next char is lower
            {
                builder.Append('-');
                builder.Append(char.ToLower(source[i]));
            }
        }
        return builder.ToString();
    }
}

Test

string[] stringArray = new[]
{
    null,
    "",
    "I",
    "IO",
    "FileIO",
    "SignalR",
    "IOStream",
    "COMObject",
    "WebAPI",
    "Windows10",
    "WindowsServer2019R2"
};

foreach (var str in stringArray)
{
    Console.WriteLine($"{str} --> {str.PascalToKebabCase()}");
}

// Output:
//  -->
//  -->
// I --> i
// IO --> io
// FileIO --> file-io
// SignalR --> signal-r
// IOStream --> io-stream
// COMObject --> com-object
// WebAPI --> web-api
// Windows10 --> windows-10
// WindowsServer2016R2 --> windows-server-2016-r-2
Rosa answered 2/1, 2019 at 19:53 Comment(0)
B
8

Here is a way to do it without using Regex:

public static string PascalToKebabCase(this string str)
{
    if (string.IsNullOrEmpty(str))
        return string.Empty;

    var builder = new StringBuilder();
    builder.Append(char.ToLower(str.First()));

    foreach (var c in str.Skip(1))
    {
        if (char.IsUpper(c))
        {
            builder.Append('-');
            builder.Append(char.ToLower(c));
        }
        else
        {
            builder.Append(c);
        }
    }

    return builder.ToString();
}

You'd have issues with well known abbreviations that use upper case letters. For example: COMObject. This solution obviously wouldn't work.

Barnsley answered 18/5, 2016 at 14:12 Comment(0)
A
4

This is what I came up with taking bits of code and Regex from others:

var pascalCase = "MyReally-CoolMFAString";
var dashCase = Regex.Replace(pascalCase, @"(?<!^)(?<!-)((?<=\p{Ll})\p{Lu}|\p{Lu}(?=\p{Ll}))", "-$1").ToLower();
Console.WriteLine(dashCase);

The output is:

my-really-cool-mfa-string

Adopt answered 2/12, 2020 at 0:24 Comment(0)
A
2

Taking inspiration from @InBetween:

public static string PascalToKebabCase(this string str)
{
    IEnumerable<char> ConvertChar(char c, int index)
    {
        if (char.IsUpper(c) && index != 0) yield return '-';
        yield return char.ToLower(c);
    }

    return string.Concat(str.SelectMany(ConvertChar));
}
Abet answered 11/3, 2021 at 16:17 Comment(0)
P
1

Taking inspiration from @johnathan-barclay:

string.Concat(str.Select((c, i) => (char.IsUpper(c) && i > 0 ? "-" : "") + char.ToLower(c)));
Pie answered 4/8, 2021 at 12:37 Comment(0)
S
0

Here is a shorter solution with Regex.Replace :

public static class KebabConverter
{
    public static string ToKebabCase(this string str)
    {
        // find and replace all parts that starts with one capital letter e.g. Net
        var str1 = Regex.Replace(str, "[A-Z][a-z]+", m => $"-{m.ToString().ToLower()}");
        
        // find and replace all parts that are all capital letter e.g. NET
        var str2 = Regex.Replace(str1, "[A-Z]+", m => $"-{m.ToString().ToLower()}");
        
        return str2.TrimStart('-');
    }
}

https://dotnetfiddle.net/WSE6sy

Socialism answered 20/10, 2020 at 11:18 Comment(0)
F
-1
        string input = "VeryLongName";
    
    char[] arr = input.ToCharArray();

    string output = Convert.ToString( arr[0]);

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

        if(char.IsUpper(arr[i]))
            output = output + "-" + Convert.ToString( arr[i]);
        else
            output = output + Convert.ToString( arr[i]);
    }

    Console.WriteLine(output.ToLower());
Faunie answered 10/9, 2021 at 18:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.