diff --git a/TJC.StringExtensions.Tests/Cases/CamelCaseExtensionsTests.cs b/TJC.StringExtensions.Tests/Cases/CamelCaseExtensionsTests.cs index 7ff4e67..0ec33f4 100644 --- a/TJC.StringExtensions.Tests/Cases/CamelCaseExtensionsTests.cs +++ b/TJC.StringExtensions.Tests/Cases/CamelCaseExtensionsTests.cs @@ -46,4 +46,18 @@ public void SplitCamelCase_FirstLetterUppercase_SplitsWithSpace() // Assert Assert.AreEqual(expected, result); } + + [TestMethod] + public void ToCamelCaseTest() + { + // Arrange + var input = "Camel Case Extensions"; + var expected = "camelCaseExtensions"; + + // Act + var result = input.ToCamelCase(); + + // Assert + Assert.AreEqual(expected, result); + } } \ No newline at end of file diff --git a/TJC.StringExtensions.Tests/Cases/KebabCaseExtensionsTests.cs b/TJC.StringExtensions.Tests/Cases/KebabCaseExtensionsTests.cs new file mode 100644 index 0000000..a56d6d4 --- /dev/null +++ b/TJC.StringExtensions.Tests/Cases/KebabCaseExtensionsTests.cs @@ -0,0 +1,21 @@ +using TJC.StringExtensions.Cases; + +namespace TJC.StringExtensions.Tests.Cases; + +[TestClass] +public class KebabCaseExtensionsTests +{ + [TestMethod] + public void ToKebabCaseTest() + { + // Arrange + var input = "Kebab Case Extensions"; + var expected = "kebab-case-extensions"; + + // Act + var result = input.ToKebabCase(); + + // Assert + Assert.AreEqual(expected, result); + } +} \ No newline at end of file diff --git a/TJC.StringExtensions.Tests/Cases/PascalCaseExtensionsTests.cs b/TJC.StringExtensions.Tests/Cases/PascalCaseExtensionsTests.cs new file mode 100644 index 0000000..51f8e1d --- /dev/null +++ b/TJC.StringExtensions.Tests/Cases/PascalCaseExtensionsTests.cs @@ -0,0 +1,21 @@ +using TJC.StringExtensions.Cases; + +namespace TJC.StringExtensions.Tests.Cases; + +[TestClass] +public class PascalCaseExtensionsTests +{ + [TestMethod] + public void ToPascalCaseTest() + { + // Arrange + var input = "Pascal Case Extensions"; + var expected = "PascalCaseExtensions"; + + // Act + var result = input.ToPascalCase(); + + // Assert + Assert.AreEqual(expected, result); + } +} \ No newline at end of file diff --git a/TJC.StringExtensions.Tests/Cases/SnakeCaseExtensionsTests.cs b/TJC.StringExtensions.Tests/Cases/SnakeCaseExtensionsTests.cs new file mode 100644 index 0000000..3d2da30 --- /dev/null +++ b/TJC.StringExtensions.Tests/Cases/SnakeCaseExtensionsTests.cs @@ -0,0 +1,21 @@ +using TJC.StringExtensions.Cases; + +namespace TJC.StringExtensions.Tests.Cases; + +[TestClass] +public class SnakeCaseExtensionsTests +{ + [TestMethod] + public void ToSnakeCaseTest() + { + // Arrange + var input = "Snake Case Extensions"; + var expected = "snake_case_extensions"; + + // Act + var result = input.ToSnakeCase(); + + // Assert + Assert.AreEqual(expected, result); + } +} \ No newline at end of file diff --git a/TJC.StringExtensions.Tests/Cases/TrainCaseExtensionsTests.cs b/TJC.StringExtensions.Tests/Cases/TrainCaseExtensionsTests.cs new file mode 100644 index 0000000..56efb80 --- /dev/null +++ b/TJC.StringExtensions.Tests/Cases/TrainCaseExtensionsTests.cs @@ -0,0 +1,21 @@ +using TJC.StringExtensions.Cases; + +namespace TJC.StringExtensions.Tests.Cases; + +[TestClass] +public class TrainCaseExtensionsTests +{ + [TestMethod] + public void ToTrainCaseTest() + { + // Arrange + var input = "Train Case Extensions"; + var expected = "Train-Case-Extensions"; + + // Act + var result = input.ToTrainCase(); + + // Assert + Assert.AreEqual(expected, result); + } +} \ No newline at end of file diff --git a/TJC.StringExtensions/Cases/CamelCaseExtensions.cs b/TJC.StringExtensions/Cases/CamelCaseExtensions.cs index 0f9690a..3373f72 100644 --- a/TJC.StringExtensions/Cases/CamelCaseExtensions.cs +++ b/TJC.StringExtensions/Cases/CamelCaseExtensions.cs @@ -9,16 +9,28 @@ public static class CamelCaseExtensions { /// /// Split camel case with a separator (typically a space). - /// - /// Example: "camelCaseExtensions" becomes "camel Case Extensions" /// /// /// - /// + /// "camelCaseExtensions" becomes "camel Case Extensions" public static string SplitCamelCase(this string? input, string separator = " ") { if (string.IsNullOrEmpty(input)) return string.Empty; return string.Concat(input.Select((x, i) => i > 0 && char.IsUpper(x) ? $"{separator}{x}" : x.ToString())); } + + /// + /// Convert any case format to camel case. + /// + /// + /// camelCase + public static string ToCamelCase(this string input) + { + var words = input.CodeCaseToWords(); + var result = new StringBuilder(words[0].ToLower()); + for (int i = 1; i < words.Length; i++) + result.Append(char.ToUpper(words[i][0]) + words[i][1..].ToLower()); + return result.ToString(); + } } \ No newline at end of file diff --git a/TJC.StringExtensions/Cases/CodeCaseExtensions.cs b/TJC.StringExtensions/Cases/CodeCaseExtensions.cs new file mode 100644 index 0000000..92d4590 --- /dev/null +++ b/TJC.StringExtensions/Cases/CodeCaseExtensions.cs @@ -0,0 +1,41 @@ +namespace TJC.StringExtensions.Cases; + +/// +/// Case extensions for strings. +/// +public static partial class CodeCaseExtensions +{ + private static readonly char[] _separator = [' ', '_', '-']; + + /// + /// Splits any code case format with a separator. + /// + /// + /// + /// + public static string SplitCodeCase(this string input, string separator = " ") + { + if (string.IsNullOrEmpty(input)) + return string.Empty; + return string.Join(separator, input.CodeCaseToWords()); + } + + /// + /// Convert any code case format to words array. + /// + /// + /// + public static string[] CodeCaseToWords(this string input) + { + if (string.IsNullOrWhiteSpace(input)) + return []; + // Add spaces around transitions (camelCase, PascalCase) and split by space, hyphen, or underscore + var spaced = CaseWordSplitter.Replace(input, " "); + return spaced.Split(_separator, StringSplitOptions.RemoveEmptyEntries); + } + + private static readonly Regex CaseWordSplitter = CaseWordSplitterRegex(); + + [GeneratedRegex(@"[a-z][A-Z]|[_\- ]", RegexOptions.Compiled)] + private static partial Regex CaseWordSplitterRegex(); +} \ No newline at end of file diff --git a/TJC.StringExtensions/Cases/KebabCaseExtensions.cs b/TJC.StringExtensions/Cases/KebabCaseExtensions.cs new file mode 100644 index 0000000..5b087a1 --- /dev/null +++ b/TJC.StringExtensions/Cases/KebabCaseExtensions.cs @@ -0,0 +1,17 @@ +namespace TJC.StringExtensions.Cases; + +/// +/// Kebab case extensions for strings. +/// +/// Example of kebab case: "kebab-case-extensions" +/// +public static class KebabCaseExtensions +{ + /// + /// Convert any case format to kebab case. + /// + /// + /// kebab-case + public static string ToKebabCase(this string input) => + string.Join("-", input.CodeCaseToWords()).ToLower(); +} \ No newline at end of file diff --git a/TJC.StringExtensions/Cases/PascalCaseExtensions.cs b/TJC.StringExtensions/Cases/PascalCaseExtensions.cs new file mode 100644 index 0000000..462a3fd --- /dev/null +++ b/TJC.StringExtensions/Cases/PascalCaseExtensions.cs @@ -0,0 +1,23 @@ +namespace TJC.StringExtensions.Cases; + +/// +/// Pascal case extensions for strings. +/// +/// Example of pascal case: "PascalCaseExtensions" +/// +public static class PascalCaseExtensions +{ + /// + /// Convert any case format to pascal case. + /// + /// + /// PascalCase + public static string ToPascalCase(this string input) + { + var words = input.CodeCaseToWords(); + var result = new StringBuilder(); + foreach (var word in words) + result.Append(char.ToUpper(word[0]) + word[1..].ToLower()); + return result.ToString(); + } +} \ No newline at end of file diff --git a/TJC.StringExtensions/Cases/SnakeCaseExtensions.cs b/TJC.StringExtensions/Cases/SnakeCaseExtensions.cs new file mode 100644 index 0000000..0765f85 --- /dev/null +++ b/TJC.StringExtensions/Cases/SnakeCaseExtensions.cs @@ -0,0 +1,17 @@ +namespace TJC.StringExtensions.Cases; + +/// +/// Snake case extensions for strings. +/// +/// Example of snake case: "snake-case-extensions" +/// +public static class SnakeCaseExtensions +{ + /// + /// Convert any case format to snake case. + /// + /// + /// snake_case + public static string ToSnakeCase(this string input) => + string.Join("_", input.CodeCaseToWords()).ToLower(); +} \ No newline at end of file diff --git a/TJC.StringExtensions/Cases/TrainCaseExtensions.cs b/TJC.StringExtensions/Cases/TrainCaseExtensions.cs new file mode 100644 index 0000000..c2f8b4c --- /dev/null +++ b/TJC.StringExtensions/Cases/TrainCaseExtensions.cs @@ -0,0 +1,18 @@ +namespace TJC.StringExtensions.Cases; + +/// +/// Train case extensions for strings. +/// +/// Example of train case: "Train-Case-Extensions" +/// +public static class TrainCaseExtensions +{ + /// + /// Convert any case format to train case. + /// + /// + /// Train-Case + public static string ToTrainCase(this string input) => + string.Join("-", input.CodeCaseToWords() + .Select(word => char.ToUpper(word[0]) + word[1..].ToLower())); +} \ No newline at end of file diff --git a/TJC.StringExtensions/GlobalUsings.cs b/TJC.StringExtensions/GlobalUsings.cs index d1ccefb..2882fc1 100644 --- a/TJC.StringExtensions/GlobalUsings.cs +++ b/TJC.StringExtensions/GlobalUsings.cs @@ -1 +1,3 @@ -global using TJC.StringExtensions.Separator; \ No newline at end of file +global using System.Text; +global using System.Text.RegularExpressions; +global using TJC.StringExtensions.Separator; \ No newline at end of file