Add string utils to core (#3738)
* Add utils to core Signed-off-by: lsiepel <leosiepel@gmail.com>pull/3845/head
parent
ae85096e53
commit
4001161810
|
@ -0,0 +1,322 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Static utility methods that are helpful when dealing with strings.
|
||||
*
|
||||
* @author Leo Siepel - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class StringUtils {
|
||||
|
||||
/**
|
||||
* If a newline char exists at the end of the line, it is removed
|
||||
*
|
||||
* <pre>
|
||||
* Util.chomp(null) = null
|
||||
* Util.chomp("") = ""
|
||||
* Util.chomp("abc \r") = "abc "
|
||||
* Util.chomp("abc\n") = "abc"
|
||||
* Util.chomp("abc\r\n") = "abc"
|
||||
* Util.chomp("abc\r\n\r\n") = "abc\r\n"
|
||||
* Util.chomp("abc\n\r") = "abc\n"
|
||||
* Util.chomp("abc\n\rabc") = "abc\n\rabc"
|
||||
* Util.chomp("\r") = ""
|
||||
* Util.chomp("\n") = ""
|
||||
* Util.chomp("\r\n") = ""
|
||||
* </pre>
|
||||
*
|
||||
* @param str the input String to escape, may be null
|
||||
* @return the chomped string, may be null
|
||||
*/
|
||||
public static @Nullable String chomp(final @Nullable String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (str.endsWith("\r\n")) {
|
||||
return str.substring(0, str.length() - 2);
|
||||
} else if (str.endsWith("\r") || str.endsWith("\n")) {
|
||||
return str.substring(0, str.length() - 1);
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple method to escape XML special characters in String.
|
||||
* There are five XML special characters which needs to be escaped:
|
||||
*
|
||||
* <pre>
|
||||
* & - &
|
||||
* < - <
|
||||
* > - >
|
||||
* " - "
|
||||
* ' - '
|
||||
* </pre>
|
||||
*
|
||||
* @param str the input xml as String to escape, may be null
|
||||
* @return the escaped xml as String, may be null
|
||||
*/
|
||||
public static @Nullable String escapeXml(@Nullable String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
|
||||
str = str.replace("&", "&");
|
||||
str = str.replace("<", "<");
|
||||
str = str.replace(">", ">");
|
||||
str = str.replace("\"", """);
|
||||
str = str.replace("'", "'");
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes a String changing the first character to title case.
|
||||
* No other characters are changed.
|
||||
*
|
||||
* <pre>
|
||||
* "" => ""
|
||||
* "cat" => "Cat"
|
||||
* "cAt" => "CAt"
|
||||
* "'cat'" => "'cat'"
|
||||
* </pre>
|
||||
*
|
||||
* @param val the String to capitalize, may be null
|
||||
* @return the capitalized String, may be null
|
||||
*/
|
||||
public static @Nullable String capitalize(@Nullable String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(str);
|
||||
sb.setCharAt(0, Character.toUpperCase(str.charAt(0)));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes words in the string. Only the first char of every word is capitalized, other are set to lowercase.
|
||||
* Words are recognized by an underscore delimiter.
|
||||
*
|
||||
* <pre>
|
||||
* "openHAB_is_cool" => "Openhab_Is_Cool"
|
||||
* "foobar_Example" => "Foobar_Example"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return the capitalized String, may be null
|
||||
*/
|
||||
public static @Nullable String capitalizeByUnderscore(@Nullable String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
|
||||
final String delimiter = "_";
|
||||
StringBuilder capitalizedFully = new StringBuilder();
|
||||
for (String splitStr : str.split(delimiter)) {
|
||||
if (splitStr.length() > 0) {
|
||||
capitalizedFully.append(splitStr.substring(0, 1).toUpperCase());
|
||||
}
|
||||
if (splitStr.length() > 1) {
|
||||
capitalizedFully.append(splitStr.substring(1).toLowerCase());
|
||||
}
|
||||
capitalizedFully.append(delimiter);
|
||||
}
|
||||
|
||||
capitalizedFully.setLength(Math.max(capitalizedFully.length() - 1, 0));
|
||||
return capitalizedFully.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes words in the string. Only the first char of every word is capitalized, the rest is left as is.
|
||||
* Words are recognized by any whitespace.
|
||||
*
|
||||
* <pre>
|
||||
* "openHAB is cool" => "OpenHAB Is Cool"
|
||||
* "foobar Example" => "Foobar Example"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to capitalize, may be null
|
||||
* @return the capitalized String, may be null
|
||||
*/
|
||||
public static @Nullable String capitalizeByWhitespace(@Nullable String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
|
||||
StringBuilder processed = new StringBuilder();
|
||||
for (String splitted : str.split("\\s+")) {
|
||||
if (splitted.length() > 1) {
|
||||
processed.append(splitted.substring(0, 1).toUpperCase());
|
||||
processed.append(splitted.substring(1));
|
||||
} else {
|
||||
processed.append(splitted.toUpperCase());
|
||||
}
|
||||
processed.append(" ");
|
||||
}
|
||||
processed.setLength(Math.max(processed.length() - 1, 0));
|
||||
return processed.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the string from the left
|
||||
*
|
||||
* <pre>
|
||||
* padLeft("9", 4, "0") => "0009"
|
||||
* padLeft("3112", 12, "*") => "********3112"
|
||||
* padLeft("openHAB", 4, "*") => "openHAB"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the String to pad, may be null
|
||||
* @param minSize the minimum String size to return
|
||||
* @param padString the String to add when padding
|
||||
* @return the padded String
|
||||
*/
|
||||
public static String padLeft(@Nullable String str, int minSize, String padString) {
|
||||
if (str == null) {
|
||||
str = "";
|
||||
}
|
||||
|
||||
return String.format("%" + minSize + "s", str).replace(" ", padString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a random string
|
||||
*
|
||||
* @param length the length of the String to return
|
||||
* @param charset the characters to use to create the String
|
||||
* @return the random String
|
||||
*/
|
||||
public static String getRandomString(int length, String charset) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
for (int i = 0; i < length; i++) {
|
||||
final int index = secureRandom.nextInt(charset.length());
|
||||
sb.append(charset.charAt(index));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a random string with [A-Zaz] characters
|
||||
*
|
||||
* @param length the length of the String to return
|
||||
* @return the random String
|
||||
*/
|
||||
public static String getRandomAlphabetic(int length) {
|
||||
return StringUtils.getRandomString(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a random string with only hex characters
|
||||
*
|
||||
* @param length the length of the String to return
|
||||
* @return the random String
|
||||
*/
|
||||
public static String getRandomHex(int length) {
|
||||
return StringUtils.getRandomString(length, "0123456789ABCDEF");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a random string with [A-Za-z0-9] characters
|
||||
*
|
||||
* @param length the length of the String to return
|
||||
* @return the random String
|
||||
*/
|
||||
public static String getRandomAlphanumeric(int length) {
|
||||
return StringUtils.getRandomString(length, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvxyz");
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the string by character type into an array
|
||||
*
|
||||
* <pre>
|
||||
* "ab de fg" => "ab", " ", "de", " ", "fg";
|
||||
* "ab de fg" => "ab", " ", "de", " ", "fg";
|
||||
* "ab:cd:ef" => "ab", ":", "cd", ":", "ef";
|
||||
* "number5" => "number", "5"
|
||||
* "fooBar" => "foo", "Bar"
|
||||
* "OHRules" => "OH", "Rules"
|
||||
* </pre>
|
||||
*
|
||||
* @param str the input String to split, may be null
|
||||
* @return the splitted String
|
||||
*/
|
||||
public static String[] splitByCharacterType(@Nullable String str) {
|
||||
if (str == null || str.isBlank()) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
List<String> cache = new ArrayList<>();
|
||||
char[] inputAsCharArray = str.toCharArray();
|
||||
int prevType = Character.getType(inputAsCharArray[0]);
|
||||
int prevTypeStart = 0;
|
||||
for (int i = prevTypeStart + 1; i < inputAsCharArray.length; i++) {
|
||||
int curType = Character.getType(inputAsCharArray[i]);
|
||||
if (prevType == curType) {
|
||||
continue;
|
||||
}
|
||||
if (curType == Character.LOWERCASE_LETTER && prevType == Character.UPPERCASE_LETTER) {
|
||||
int tmpStart = i - 1;
|
||||
if (tmpStart != prevTypeStart) {
|
||||
cache.add(new String(inputAsCharArray, prevTypeStart, tmpStart - prevTypeStart));
|
||||
prevTypeStart = tmpStart;
|
||||
}
|
||||
} else {
|
||||
cache.add(new String(inputAsCharArray, prevTypeStart, i - prevTypeStart));
|
||||
prevTypeStart = i;
|
||||
}
|
||||
prevType = curType;
|
||||
}
|
||||
cache.add(new String(inputAsCharArray, prevTypeStart, inputAsCharArray.length - prevTypeStart));
|
||||
return cache.toArray(String[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple method to un escape XML special characters in String.
|
||||
* There are five XML Special characters which needs to be escaped:
|
||||
*
|
||||
* <pre>
|
||||
* & => &
|
||||
* < => <
|
||||
* > => >
|
||||
* " => "
|
||||
* ' => '
|
||||
* </pre>
|
||||
*
|
||||
* @param input the input xml as String to unescape, may be null
|
||||
* @return the unescaped xml as String, may be null
|
||||
*/
|
||||
public static @Nullable String unEscapeXml(@Nullable String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
str = str.replace("&", "&");
|
||||
str = str.replace("<", "<");
|
||||
str = str.replace(">", ">");
|
||||
str = str.replace(""", "\"");
|
||||
str = str.replace("'", "'");
|
||||
return str;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
|
||||
package org.openhab.core.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* The {@link StringUtils} class defines some static string utility methods
|
||||
*
|
||||
* @author Leo Siepel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class StringUtilsTest {
|
||||
|
||||
@Test
|
||||
public void chompTest() {
|
||||
assertEquals("", StringUtils.chomp(""));
|
||||
assertEquals(null, StringUtils.chomp(null));
|
||||
assertEquals("abc ", StringUtils.chomp("abc \r"));
|
||||
assertEquals("abc", StringUtils.chomp("abc\n"));
|
||||
assertEquals("abc", StringUtils.chomp("abc\r\n"));
|
||||
assertEquals("abc\r\n", StringUtils.chomp("abc\r\n\r\n"));
|
||||
assertEquals("abc\n", StringUtils.chomp("abc\n\r"));
|
||||
assertEquals("abc\n\rabc", StringUtils.chomp("abc\n\rabc"));
|
||||
assertEquals("", StringUtils.chomp("\r"));
|
||||
assertEquals("", StringUtils.chomp("\n"));
|
||||
assertEquals("", StringUtils.chomp("\r\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void escapeXmlTest() {
|
||||
assertEquals(null, StringUtils.escapeXml(null));
|
||||
assertEquals(" ", StringUtils.escapeXml(" "));
|
||||
assertEquals("invalidxml", StringUtils.escapeXml("invalidxml"));
|
||||
assertEquals("<xmlExample>&</xmlExample>", StringUtils.escapeXml("<xmlExample>&</xmlExample>"));
|
||||
assertEquals("<xmlExample>"</xmlExample>",
|
||||
StringUtils.escapeXml("<xmlExample>\"</xmlExample>"));
|
||||
assertEquals("<xmlExample>'</xmlExample>",
|
||||
StringUtils.escapeXml("<xmlExample>\'</xmlExample>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void capitalizeTest() {
|
||||
assertEquals(null, StringUtils.capitalize(null));
|
||||
assertEquals(" ", StringUtils.capitalize(" "));
|
||||
assertEquals("Cat", StringUtils.capitalize("cat"));
|
||||
assertEquals("CAt", StringUtils.capitalize("cAt"));
|
||||
assertEquals("'cat'", StringUtils.capitalize("'cat'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void capitalizeAllWordsTest() {
|
||||
assertEquals(null, StringUtils.capitalizeByUnderscore(null));
|
||||
assertEquals("Openhab_Is_Cool", StringUtils.capitalizeByUnderscore("openHAB_is_cool"));
|
||||
assertEquals("Foobar_Example", StringUtils.capitalizeByUnderscore("foobar_Example"));
|
||||
assertEquals("'another_Test'", StringUtils.capitalizeByUnderscore("'another_test'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void capitalizeWordsTest() {
|
||||
assertEquals("OpenHAB Is Cool", StringUtils.capitalizeByWhitespace("openHAB is cool"));
|
||||
assertEquals("Foobar Example", StringUtils.capitalizeByWhitespace("foobar Example"));
|
||||
assertEquals("'another Test'", StringUtils.capitalizeByWhitespace("'another test'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRandomString() {
|
||||
String randomstring = StringUtils.getRandomString(10000, "123");
|
||||
assertEquals(6666, randomstring.replace("1", "").length(), 333,
|
||||
"randomString does not equaly (<5% delta) use all characters in set");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void padLeft() {
|
||||
assertEquals("000000", StringUtils.padLeft("", 6, "0"));
|
||||
assertEquals("000000", StringUtils.padLeft(null, 6, "0"));
|
||||
assertEquals("000teststr", StringUtils.padLeft("teststr", 10, "0"));
|
||||
assertEquals("AAAAAAp3RF@CT", StringUtils.padLeft("p3RF@CT", 13, "A"));
|
||||
assertEquals("nopaddingshouldhappen", StringUtils.padLeft("nopaddingshouldhappen", 21, "x"));
|
||||
assertEquals("LongerStringThenMinSize", StringUtils.padLeft("LongerStringThenMinSize", 10, "x"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void splitByCharacterType() {
|
||||
assertArrayEquals(new String[0], StringUtils.splitByCharacterType(null));
|
||||
assertArrayEquals(new String[0], StringUtils.splitByCharacterType(""));
|
||||
assertArrayEquals(new String[] { "ab", " ", "de", " ", "fg" }, StringUtils.splitByCharacterType("ab de fg"));
|
||||
assertArrayEquals(new String[] { "ab", " ", "de", " ", "fg" },
|
||||
StringUtils.splitByCharacterType("ab de fg"));
|
||||
assertArrayEquals(new String[] { "ab", ":", "cd", ":", "ef" }, StringUtils.splitByCharacterType("ab:cd:ef"));
|
||||
assertArrayEquals(new String[] { "number", "5" }, StringUtils.splitByCharacterType("number5"));
|
||||
assertArrayEquals(new String[] { "foo", "Bar" }, StringUtils.splitByCharacterType("fooBar"));
|
||||
assertArrayEquals(new String[] { "foo", "200", "Bar" }, StringUtils.splitByCharacterType("foo200Bar"));
|
||||
assertArrayEquals(new String[] { "ASF", "Rules" }, StringUtils.splitByCharacterType("ASFRules"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue