Repository: commons-text Updated Branches: refs/heads/master 2035ed14f -> 9f6e5e45e
TEXT-85:Added CaseUtils class with camel case conversion Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/f2626183 Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/f2626183 Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/f2626183 Branch: refs/heads/master Commit: f2626183fcf7d92fd51be24da92f033c8c22f957 Parents: 5f498c0 Author: Arun Vinud <arunvinud.sivasubramaniansurianaraya...@capitalone.com> Authored: Fri Jun 16 01:09:06 2017 -0400 Committer: Arun Vinud <arunvinud.sivasubramaniansurianaraya...@capitalone.com> Committed: Fri Jun 16 01:09:06 2017 -0400 ---------------------------------------------------------------------- .../java/org/apache/commons/text/CaseUtils.java | 140 +++++++++++++++++++ .../org/apache/commons/text/CaseUtilsTest.java | 80 +++++++++++ 2 files changed, 220 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-text/blob/f2626183/src/main/java/org/apache/commons/text/CaseUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/text/CaseUtils.java b/src/main/java/org/apache/commons/text/CaseUtils.java new file mode 100644 index 0000000..0e313a4 --- /dev/null +++ b/src/main/java/org/apache/commons/text/CaseUtils.java @@ -0,0 +1,140 @@ +/* + * 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 org.apache.commons.lang3.StringUtils; + +import java.util.HashSet; +import java.util.Set; + +/** + * <p>Case manipulation operations on Strings that contain words.</p> + * + * <p>This class tries to handle <code>null</code> input gracefully. + * An exception will not be thrown for a <code>null</code> input. + * Each method documents its behaviour in more detail.</p> + * + * @since 1.0 + */ +public class CaseUtils { + + /** + * <p><code>CaseUtils</code> instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * <code>CaseUtils.toCamelCase("foo bar", true, new char[]{'-'});</code>.</p> + * <p> + * <p>This constructor is public to permit tools that require a JavaBean + * instance to operate.</p> + */ + public CaseUtils() { + super(); + } + + // Camel Case + //----------------------------------------------------------------------- + /** + * <p>Converts all the delimiter separated words in a String into camelCase, + * that is each word is made up of a titlecase character and then a series of + * lowercase characters. The </p> + * + * <p>The delimiters represent a set of characters understood to separate words. + * The first non-delimiter character after a delimiter will be capitalized. The first String + * character may or may not be capitalized and it's determined by the user input for capitalizeFirstLetter + * variable.</p> + * + * <p>A <code>null</code> input String returns <code>null</code>. + * Capitalization uses the Unicode title case, normally equivalent to + * upper case and cannot perform locale-sensitive mappings.</p> + * + * <pre> + * CaseUtils.toCamelCase(null, false) = null + * CaseUtils.toCamelCase("", false, *) = "" + * CaseUtils.toCamelCase(*, false, null) = * + * CaseUtils.toCamelCase(*, true, new char[0]) = * + * CaseUtils.toCamelCase("To.Camel.Case", false, new char[]{'.'}) = "toCamelCase" + * CaseUtils.toCamelCase(" to @ Camel case", true, new char[]{'@'}) = "ToCamelCase" + * CaseUtils.toCamelCase(" @to @ Camel case", false, new char[]{'@'}) = "toCamelCase" + * </pre> + * + * @param str the String to be converted to camelCase, may be null + * @param capitalizeFirstLetter boolean that determines if the first character of first word should be title case. + * @param delimiters set of characters to determine capitalization, null and/or empty array means whitespace + * @return camelCase of String, <code>null</code> if null String input + */ + public static String toCamelCase(String str, final boolean capitalizeFirstLetter, final char... delimiters) { + if (StringUtils.isEmpty(str)) { + return str; + } + str = str.toLowerCase(); + int strLen = str.length(); + int [] newCodePoints = new int[strLen]; + int outOffset = 0; + Set<Integer> delimiterSet = generateDelimiterSet(delimiters); + boolean capitalizeNext = false; + if (capitalizeFirstLetter) { + capitalizeNext = true; + } + for (int index = 0; index < strLen;) { + final int codePoint = str.codePointAt(index); + + if (delimiterSet.contains(codePoint)) { + capitalizeNext = true; + if (outOffset == 0) { + capitalizeNext = false; + } + index += Character.charCount(codePoint); + } else if (capitalizeNext || outOffset == 0 && capitalizeFirstLetter) { + int titleCaseCodePoint = Character.toTitleCase(codePoint); + newCodePoints[outOffset++] = titleCaseCodePoint; + index += Character.charCount(titleCaseCodePoint); + capitalizeNext = false; + } else { + newCodePoints[outOffset++] = codePoint; + index += Character.charCount(codePoint); + } + } + if (outOffset != 0) { + return new String(newCodePoints, 0, outOffset); + } else { + return str; + } + + } + + /** + * <p>Converts an array of delimiters to a hash set of code points. Code point of space(32) is added + * as the default value. The generated hash set provides O(1) + * lookup time .</p> + * + * @param delimiters set of characters to determine capitalization, null means whitespace + * @return Set<Integer> + */ + private static Set<Integer> generateDelimiterSet(final char[] delimiters) { + Set<Integer> delimiterHashSet = new HashSet<Integer>(); + delimiterHashSet.add(Character.codePointAt(new char[]{' '}, 0)); + if (delimiters == null || delimiters.length == 0) { + return delimiterHashSet; + } + + for (int index = 0; index < delimiters.length; index++) { + delimiterHashSet.add(Character.codePointAt(delimiters, index)); + } + return delimiterHashSet; + + } +} + http://git-wip-us.apache.org/repos/asf/commons-text/blob/f2626183/src/test/java/org/apache/commons/text/CaseUtilsTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/text/CaseUtilsTest.java b/src/test/java/org/apache/commons/text/CaseUtilsTest.java new file mode 100644 index 0000000..0f3cabf --- /dev/null +++ b/src/test/java/org/apache/commons/text/CaseUtilsTest.java @@ -0,0 +1,80 @@ +/* + * 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 org.junit.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link CaseUtils} class. + */ +public class CaseUtilsTest { + + //----------------------------------------------------------------------- + @Test + public void testConstructor() { + assertNotNull(new CaseUtils()); + final Constructor<?>[] cons = CaseUtils.class.getDeclaredConstructors(); + assertEquals(1, cons.length); + assertTrue(Modifier.isPublic(cons[0].getModifiers())); + assertTrue(Modifier.isPublic(CaseUtils.class.getModifiers())); + assertFalse(Modifier.isFinal(CaseUtils.class.getModifiers())); + } + + //------------------------------------------------------------------------ + @Test + public void testToCamelCase() throws Exception { + assertEquals(null, CaseUtils.toCamelCase(null, false,null)); + assertEquals("", CaseUtils.toCamelCase("", true, null)); + assertEquals(" ", CaseUtils.toCamelCase(" ", false, null)); + assertEquals("aBC@def", CaseUtils.toCamelCase("a b c @def", false, null)); + assertEquals("ABC@def", CaseUtils.toCamelCase("a b c @def", true, new char[]{})); + assertEquals("ABC@def", CaseUtils.toCamelCase("a b c @def", true, new char[]{'-'})); + assertEquals("ABC@def", CaseUtils.toCamelCase("a b c @def", true, new char[]{'-'})); + + char[] chars = new char[] { '-', '+', ' ', '@' }; + assertEquals("-+@ ", CaseUtils.toCamelCase("-+@ ", true, chars)); + assertEquals("toCamelCase", CaseUtils.toCamelCase(" to-CAMEL-cASE", false, chars)); + assertEquals("ToCamelCase", CaseUtils.toCamelCase("@@@@ to+CAMEL@cASE ", true, chars)); + assertEquals("ToCaMeLCase", CaseUtils.toCamelCase("To+CA+ME L@cASE", true, chars)); + + assertEquals("toCamelCase", CaseUtils.toCamelCase("To.Camel.Case", false, new char[]{'.'})); + assertEquals("toCamelCase", CaseUtils.toCamelCase("To.Camel-Case", false, new char[]{'-', '.'})); + assertEquals("toCamelCase", CaseUtils.toCamelCase(" to @ Camel case", false, new char[]{'-', '@'})); + assertEquals("ToCamelCase", CaseUtils.toCamelCase(" @to @ Camel case", true, new char[]{'-', '@'})); + + assertEquals("ToCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", true, null)); + assertEquals("toCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", false, null)); + assertEquals("toCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", false, null)); + assertEquals("tocamelcase", CaseUtils.toCamelCase("tocamelcase", false, null)); + assertEquals("Tocamelcase", CaseUtils.toCamelCase("tocamelcase", true, null)); + assertEquals("tocamelcase", CaseUtils.toCamelCase("Tocamelcase", false, null)); + + assertEquals("Tocamelcase", CaseUtils.toCamelCase("tocamelcase", true)); + assertEquals("tocamelcase", CaseUtils.toCamelCase("tocamelcase", false)); + + assertEquals("\uD800\uDF00\uD800\uDF02", CaseUtils.toCamelCase("\uD800\uDF00 \uD800\uDF02", true)); + assertEquals("\uD800\uDF00\uD800\uDF01\uD800\uDF02\uD800\uDF03", CaseUtils.toCamelCase("\uD800\uDF00\uD800\uDF01\uD800\uDF14\uD800\uDF02\uD800\uDF03", true, new char[]{'\uD800', '\uDF14'})); + } +} \ No newline at end of file