You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by cl...@apache.org on 2024/05/25 09:42:54 UTC
(commons-text) 01/01: initial implementation
This is an automated email from the ASF dual-hosted git repository.
claude pushed a commit to branch TEXT-217_Add_SnakeCase_Parsing
in repository https://gitbox.apache.org/repos/asf/commons-text.git
commit 7532dcb7bd0f8905391a491d428f195e8d7cbb0e
Author: Claude Warren <cl...@xenei.com>
AuthorDate: Sat May 25 11:42:22 2024 +0200
initial implementation
---
.../java/org/apache/commons/text/CasedString.java | 143 +++++++++++++++++++++
.../org/apache/commons/text/CasedStringTest.java | 47 +++++++
2 files changed, 190 insertions(+)
diff --git a/src/main/java/org/apache/commons/text/CasedString.java b/src/main/java/org/apache/commons/text/CasedString.java
new file mode 100644
index 00000000..a89cd862
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/CasedString.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Handles converting from one string case to another (e.g. camel case to snake case).
+ */
+public class CasedString {
+ private String string;
+ private StringCase stringCase;
+
+ /**
+ * A method to join camel string fragments together.
+ */
+ private final static Function<String[],String> camelJoiner = a -> {
+ StringBuilder sb = new StringBuilder(a[0]);
+
+ for (int i=1;i<a.length;i++) {
+ sb.append(WordUtils.capitalize(a[i]));
+ }
+ return sb.toString();
+ };
+
+ /**
+ * An enumeration of supported string cases.
+ */
+ public enum StringCase {
+ /**
+ * Camel case identifies strings like 'CamelCase'.
+ */
+ Camel(Character::isUpperCase, true, camelJoiner),
+ /**
+ * Snake case identifies strings like 'Snake_Case'
+ */
+ Snake(c -> c =='_', false, a -> String.join("_", a)),
+ /**
+ * Kebab case identifies strings like 'kebab-case'
+ */
+ Kebab(c -> c == '-', false, a -> String.join("-", a)),
+
+ /**
+ * Phrase case identifies phrases of words like 'phrase case'
+ */
+ Phrase(c -> c == ' ', false, a -> String.join(" ", a)),
+
+ /**
+ * Dot case identifies strings of words like 'dot.case'
+ */
+ Dot(c -> c == '.', false, a -> String.join(".", a));
+
+ private final Predicate<Character> splitter;
+ private final boolean preserveSplit;
+ private final Function<String[],String> joiner;
+
+ /**
+ * Defines a String Case
+ * @param splitter The predicate that determines when a new word in the cased string begins.
+ * @param preserveSplit if {@code true} the character that the splitter detected is preserved as the first character of the new word.
+ * @param joiner The function to merge a list of strings into the cased String.
+ */
+ StringCase(final Predicate<Character> splitter, final boolean preserveSplit, final Function<String[],String> joiner) {
+ this.splitter = splitter;
+ this.preserveSplit = preserveSplit;
+ this.joiner = joiner;
+ }
+ }
+
+ /**
+ * A representation of a cased string and the identified case of that string.
+ * @param stringCase The {@code StringCase} that the {@code string} argument is in.
+ * @param string The string.
+ */
+ public CasedString(StringCase stringCase, String string) {
+ this.string = string;
+ this.stringCase = stringCase;
+ }
+
+ private String[] split() {
+ List<String> lst = new ArrayList<>();
+ StringBuilder sb = new StringBuilder();
+ for (char c : string.toCharArray())
+ {
+ if (stringCase.splitter.test(c)) {
+ if (sb.length() > 0) {
+ lst.add(sb.toString());
+ sb.setLength(0);
+ }
+ if (stringCase.preserveSplit) {
+ sb.append(c);
+ }
+ } else {
+ sb.append(c);
+ }
+ }
+ if (sb.length() > 0) {
+ lst.add(sb.toString());
+ }
+ return lst.toArray(new String[0]);
+ }
+
+ /**
+ * Converts this cased string into a {@code String} of another format.
+ * The upper/lower case of the characters within the string are not modified.
+ * @param stringCase THe fomrat to convert to.
+ * @return the String current string represented in the new format.
+ */
+ public String toCase(StringCase stringCase) {
+ if (stringCase == this.stringCase) {
+ return string;
+ }
+ return stringCase.joiner.apply(split());
+ }
+
+ /**
+ * Returns the string representation provided in the constructor.
+ * @return the string representation.
+ */
+ @Override
+ public String toString() {
+ return string;
+ }
+}
diff --git a/src/test/java/org/apache/commons/text/CasedStringTest.java b/src/test/java/org/apache/commons/text/CasedStringTest.java
new file mode 100644
index 00000000..14ccc781
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/CasedStringTest.java
@@ -0,0 +1,47 @@
+package org.apache.commons.text;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CasedStringTest {
+
+ private static String expectedValue(CasedString.StringCase stringCase) {
+ switch (stringCase) {
+ case Camel:
+ return "HelloWorld";
+ case Kebab:
+ return "Hello-World";
+ case Phrase:
+ return "Hello World";
+ case Snake:
+ return "Hello_World";
+ case Dot:
+ return "Hello.World";
+ default:
+ throw new RuntimeException("Unsupported StringCase: " + stringCase);
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("conversionProvider")
+ public void testConversions(CasedString underTest) {
+ for (CasedString.StringCase stringCase : CasedString.StringCase.values()) {
+ assertEquals(expectedValue(stringCase), underTest.toCase(stringCase), () -> "failed converting to " + stringCase);
+ }
+ }
+
+ private static Stream<Arguments> conversionProvider() {
+ List<Arguments> lst = new ArrayList<>();
+ for (CasedString.StringCase stringCase : CasedString.StringCase.values()) {
+ lst.add(Arguments.of(new CasedString(stringCase, expectedValue(stringCase))));
+ }
+ return lst.stream();
+ }
+}