Skip to content

Instantly share code, notes, and snippets.

@damieng
Created August 14, 2023 07:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save damieng/565eb167b4f3179bb21abecd9b7a44b3 to your computer and use it in GitHub Desktop.
Save damieng/565eb167b4f3179bb21abecd9b7a44b3 to your computer and use it in GitHub Desktop.
Camel Case and Title Case with smart word boundaries for C#
using System.Globalization;
using System.Text.RegularExpressions;
namespace MongoDB.EntityFrameworkCore;
/// <summary>
/// A variety of helper methods for creating names.
/// </summary>
public static partial class NamingHelperMethods
{
/// <summary>
/// Converts a given string to camel case.
/// </summary>
/// <param name="input">The input string to convert.</param>
/// <param name="culture">The culture to use in upper-casing and lower-casing letters.</param>
/// <returns>The cleaned camel-cased string.</returns>
/// <remarks>Word boundaries are considered spaces, non-alphanumeric, a transition from
/// lower to upper, and a transition from number to non-number.</remarks>
public static string ToCamelCase(this string input, CultureInfo culture)
{
if (string.IsNullOrEmpty(input)) return input;
string[] words = WordSplitRegex().Split(input);
char[] result = new char[input.Length];
int outIndex = 0;
for (int inIndex = 0; inIndex < words.Length; inIndex++)
{
string w = words[inIndex];
if (w.Length == 0) continue;
if (inIndex == 0)
{
result[outIndex] = char.ToLower(w[0], culture);
}
else
{
result[outIndex] = char.ToUpper(w[0], culture);
}
w.ToLower(culture).CopyTo(1, result, outIndex + 1, w.Length - 1);
outIndex += w.Length;
}
return new string(result, 0, outIndex);
}
/// <summary>
/// Converts a given string to title case.
/// </summary>
/// <param name="input">The input string to convert.</param>
/// <param name="culture">The culture to use in upper-casing and lower-casing letters.</param>
/// <returns>The cleaned title-cased string.</returns>
/// <remarks>Word boundaries are considered spaces, non-alphanumeric, a transition from
/// lower to upper, and a transition from number to non-number.</remarks>
public static string ToTitleCase(this string input, CultureInfo culture)
{
if (string.IsNullOrEmpty(input)) return input;
string[] words = WordSplitRegex().Split(input);
char[] result = new char[input.Length];
int outIndex = 0;
for (int inIndex = 0; inIndex < words.Length; inIndex++)
{
string w = words[inIndex];
if (w.Length == 0) continue;
result[outIndex] = char.ToUpper(w[0], culture);
w.ToLower(culture).CopyTo(1, result, outIndex + 1, w.Length - 1);
outIndex += w.Length;
}
return new string(result, 0, outIndex);
}
// Find word boundaries.
// Word boundaries are considered spaces, non-alphanumeric, a transition from lower to upper,
// and a transition from number to non-number.
[GeneratedRegex(@"(?<=\p{Ll})(?=\p{Lu})|[\s\p{P}]|(?<=\p{Lu}{2,})(?=\p{Ll})|(?<=\p{N})(?=\P{N})")]
private static partial Regex WordSplitRegex();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment