From 30d56c276f3518e7341b42d4f4228dd8fde2db0f Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:44:56 -0400 Subject: [PATCH 1/8] Create common code case extensions --- .../Cases/CodeCaseExtensions.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 TJC.StringExtensions/Cases/CodeCaseExtensions.cs 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 From 8604fd60da91d795d4d539647c20626fd527554f Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:07 -0400 Subject: [PATCH 2/8] Create ToCamelCase Extension --- .../Cases/CamelCaseExtensions.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) 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 From c0df49dff7d1d8cdbdb1e95f33fada51a988d1d8 Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:13 -0400 Subject: [PATCH 3/8] Create ToKebabCase Extension --- .../Cases/KebabCaseExtensions.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 TJC.StringExtensions/Cases/KebabCaseExtensions.cs 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 From 1b7903447762be8e3c1f6edc118dfba1eec5bd87 Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:19 -0400 Subject: [PATCH 4/8] Create ToSnakeCase Extension --- .../Cases/SnakeCaseExtensions.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 TJC.StringExtensions/Cases/SnakeCaseExtensions.cs 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 From b0d0b2c584e8483290a0713ad5cf746720663b4d Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:25 -0400 Subject: [PATCH 5/8] Create ToPascalCase Extension --- .../Cases/PascalCaseExtensions.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 TJC.StringExtensions/Cases/PascalCaseExtensions.cs 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 From 818333c0e516ef32078b300770ee40e8a2d14cda Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:32 -0400 Subject: [PATCH 6/8] Create ToTrainCase Extension --- .../Cases/TrainCaseExtensions.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 TJC.StringExtensions/Cases/TrainCaseExtensions.cs 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 From fe4f2058346f38f9ee45f294f70180ca23275a8d Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:38 -0400 Subject: [PATCH 7/8] Global usings --- TJC.StringExtensions/GlobalUsings.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From d193240e966b68fb9905706350c37a8fe66b478a Mon Sep 17 00:00:00 2001 From: Tyler Carrol Date: Fri, 25 Oct 2024 19:45:56 -0400 Subject: [PATCH 8/8] Create Tests for ToCase Extensions --- .../Cases/CamelCaseExtensionsTests.cs | 14 +++++++++++++ .../Cases/KebabCaseExtensionsTests.cs | 21 +++++++++++++++++++ .../Cases/PascalCaseExtensionsTests.cs | 21 +++++++++++++++++++ .../Cases/SnakeCaseExtensionsTests.cs | 21 +++++++++++++++++++ .../Cases/TrainCaseExtensionsTests.cs | 21 +++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 TJC.StringExtensions.Tests/Cases/KebabCaseExtensionsTests.cs create mode 100644 TJC.StringExtensions.Tests/Cases/PascalCaseExtensionsTests.cs create mode 100644 TJC.StringExtensions.Tests/Cases/SnakeCaseExtensionsTests.cs create mode 100644 TJC.StringExtensions.Tests/Cases/TrainCaseExtensionsTests.cs 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