10

I'm trying to convert PascalCase property names such as Is24Hour, Is512 to JSON-style lowercase with underscores (ie. is_24_hour, is_512) using C#.

So far I've got far but it doesn't work for multiple numbers.

([A-Z])([A-Z0-9][a-z])|([a-z0-9])([A-Z0-9])

With the replacement expression ($1$3_$2$4)

For example "Is24Hour" becomes "Is_24_Hour" (which is then lower-cased by .ToLower()). but "Is512" becomes "Is_51_2".

knocte
  • 16,941
  • 11
  • 79
  • 125
Jamie
  • 4,670
  • 5
  • 35
  • 49

3 Answers3

9

Use String.ToLower for conversion into lowercase.

For the regex, the following seems to work:

((?<=.)[A-Z][a-zA-Z]*)|((?<=[a-zA-Z])\d+)

combined with the replacement expression:

_$1$2

Here's a full sample:

string strRegex = @"((?<=.)[A-Z][a-zA-Z]*)|((?<=[a-zA-Z])\d+)";
Regex myRegex = new Regex(strRegex, RegexOptions.Multiline);
string strTargetString = @"Is24Hour" + "\n" + 
    @"Is512" + "\n" + @"A12Hour4" + "\n" + 
    @"23AHourDay12" + "\n" + @"An8DAY512";

string strReplace = @"_$1$2";

return myRegex.Replace(strTargetString, strReplace).ToLower();
Arad Alvand
  • 8,607
  • 10
  • 51
  • 71
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • 2
    Thanks, that works perfectly. Sorry I forgot to add the replacement expression to my question :) – Jamie Jan 06 '14 at 14:26
  • 2
    This does not work properly at all. See [this fiddle](https://dotnetfiddle.net/JOS1Jm). Even using the exact example that's provided results in an invalid result string. For example, `23AHourDay12` becomes `23_ahourday_12` with this code, but it should be `23_a_hour_day_12`. – vaindil Jul 16 '18 at 15:12
  • This doesn't work at all. `FooBarBuzz` is converted into `foo_barbuzz`! – Arad Alvand May 12 '23 at 19:25
3

The accepted solution does not work for strings like "23AHourDay12", it produces "23_ahourday_12", but should "23_a_hour_day_12" (see the @vaindil comment)

Here is a solution using Linq, instead of Regex:

public static class ExtensionMethods {
    public static string ToUnderscoreCase(this string str) {
        return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower();
    }
}

Thanks @vkobel github user. Source: https://gist.github.com/vkobel/d7302c0076c64c95ef4b

Konstantin Gindemit
  • 382
  • 1
  • 4
  • 10
2
public string PascalCaseToSnakeCase(string str) => Regex.Replace(str, "[A-Z0-9][0-9]*", "_$0").ToLower().Trim('_');
Srikanth Remani
  • 101
  • 1
  • 9