From 76f68f4b1bd8b1a2cd4fc829c6b8afa04f211e54 Mon Sep 17 00:00:00 2001 From: shailendra Date: Mon, 4 Nov 2024 13:37:10 +0530 Subject: [PATCH] Add toSnakeCase method to StringUtils --- .../org/apache/commons/lang3/StringUtils.java | 45 +++++++++++++++++++ .../apache/commons/lang3/StringUtilsTest.java | 17 +++++++ 2 files changed, 62 insertions(+) diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index 70c26ee315b..482f46be1b8 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -9332,6 +9332,51 @@ public static String wrapIfMissing(final String str, final String wrapWith) { return builder.toString(); } + /** + * Converts a camelCase string to snake_case. + *
+     * StringUtils.toSnakeCase(null)                   = null
+     * StringUtils.toSnakeCase("")                     = ""
+     * StringUtils.toSnakeCase("simple")               = "simple"
+     * StringUtils.toSnakeCase("camelCase")            = "camel_case"
+     * StringUtils.toSnakeCase("CamelCase")            = "camel_case"
+     * StringUtils.toSnakeCase("thisIsATest")          = "this_is_a_test"
+     * StringUtils.toSnakeCase("JSONParser")           = "json_parser"
+     * StringUtils.toSnakeCase("already_snake_case")   = "already_snake_case"
+     * StringUtils.toSnakeCase("A")                    = "a"
+     * StringUtils.toSnakeCase("HelloWorld")           = "hello_world"
+     * StringUtils.toSnakeCase("multipleUPPERCases")   = "multiple_upper_cases"
+     * 
+ * @param str the camelCase string to be converted, may be {@code null} + * @return the snake_case version of the input string + */ + public static String toSnakeCase(String str) { + if (str == null || str.isEmpty()) { + return str; + } + + StringBuilder result = new StringBuilder(); + char prevChar = str.charAt(0); + result.append(Character.toLowerCase(prevChar)); // Initialize with the first character in lowercase + + for (int i = 1; i < str.length(); i++) { + char currentChar = str.charAt(i); + + if (Character.isUpperCase(currentChar)) { + // Add underscore if the previous character is not uppercase or if the next character is lowercase + if (!Character.isUpperCase(prevChar) || (i + 1 < str.length() && Character.isLowerCase(str.charAt(i + 1)))) { + result.append('_'); + } + result.append(Character.toLowerCase(currentChar)); + } else { + result.append(currentChar); + } + + prevChar = currentChar; + } + return result.toString(); + } + /** * {@link StringUtils} instances should NOT be constructed in * standard programming. Instead, the class should be used as diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java index 8f15669b329..433a251468d 100644 --- a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java @@ -3431,4 +3431,21 @@ public void testWrapIfMissing_StringString() { assertSame("ab/ab", StringUtils.wrapIfMissing("ab/ab", "ab")); assertSame("//x//", StringUtils.wrapIfMissing("//x//", "//")); } + + /** + * Tests {@code toSnakeCase}. + */ + @Test + public void testToSnakeCase() { + assertEquals("camel_case", StringUtils.toSnakeCase("camelCase")); + assertEquals("json_parser", StringUtils.toSnakeCase("JSONParser")); + assertEquals("simple", StringUtils.toSnakeCase("simple")); + assertEquals("this_is_a_test_string", StringUtils.toSnakeCase("thisIsATestString")); + assertEquals("", StringUtils.toSnakeCase("")); + assertEquals("a", StringUtils.toSnakeCase("A")); + assertEquals("hello_world", StringUtils.toSnakeCase("HelloWorld")); + assertEquals("multiple_upper_cases", StringUtils.toSnakeCase("multipleUPPERCases")); + assertNull(StringUtils.toSnakeCase(null)); + assertEquals("already_snake_case", StringUtils.toSnakeCase("already_snake_case")); + } }