org.apache.camel.util.StringHelper Maven / Gradle / Ivy
The newest version!
/*
* 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.camel.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* Helper methods for working with Strings.
*/
public final class StringHelper {
/**
* Constructor of utility class should be private.
*/
private StringHelper() {
}
/**
* Ensures that s
is friendly for a URL or file system.
*
* @param s String to be sanitized.
* @return sanitized version of s
.
* @throws NullPointerException if s
is null
.
*/
public static String sanitize(final String s) {
return s.replace(':', '-')
.replace('_', '-')
.replace('.', '-')
.replace('/', '-')
.replace('\\', '-');
}
/**
* Remove carriage return and line feeds from a String, replacing them with an empty String.
*
* @param s String to be sanitized of carriage return / line feed characters
* @return sanitized version of s
.
* @throws NullPointerException if s
is null
.
*/
public static String removeCRLF(String s) {
return s
.replace("\r", "")
.replace("\n", "");
}
/**
* Counts the number of times the given char is in the string
*
* @param s the string
* @param ch the char
* @return number of times char is located in the string
*/
public static int countChar(String s, char ch) {
return countChar(s, ch, -1);
}
/**
* Counts the number of times the given char is in the string
*
* @param s the string
* @param ch the char
* @param end end index
* @return number of times char is located in the string
*/
public static int countChar(String s, char ch, int end) {
if (s == null || s.isEmpty()) {
return 0;
}
int matches = 0;
int len = end < 0 ? s.length() : end;
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (ch == c) {
matches++;
}
}
return matches;
}
/**
* Limits the length of a string
*
* @param s the string
* @param maxLength the maximum length of the returned string
* @return s if the length of s is less than maxLength or the first maxLength characters of s
*/
public static String limitLength(String s, int maxLength) {
if (ObjectHelper.isEmpty(s)) {
return s;
}
return s.length() <= maxLength ? s : s.substring(0, maxLength);
}
/**
* Removes all quotes (single and double) from the string
*
* @param s the string
* @return the string without quotes (single and double)
*/
public static String removeQuotes(final String s) {
if (ObjectHelper.isEmpty(s)) {
return s;
}
return s.replace("'", "")
.replace("\"", "");
}
/**
* Removes all leading and ending quotes (single and double) from the string
*
* @param s the string
* @return the string without leading and ending quotes (single and double)
*/
public static String removeLeadingAndEndingQuotes(final String s) {
if (ObjectHelper.isEmpty(s)) {
return s;
}
String copy = s.trim();
if (copy.length() < 2) {
return s;
}
if (copy.startsWith("'") && copy.endsWith("'")) {
return copy.substring(1, copy.length() - 1);
}
if (copy.startsWith("\"") && copy.endsWith("\"")) {
return copy.substring(1, copy.length() - 1);
}
// no quotes, so return as-is
return s;
}
/**
* Whether the string starts and ends with either single or double quotes.
*
* @param s the string
* @return true if the string starts and ends with either single or double quotes.
*/
public static boolean isQuoted(String s) {
return isSingleQuoted(s) || isDoubleQuoted(s);
}
/**
* Whether the string starts and ends with single quotes.
*
* @param s the string
* @return true if the string starts and ends with single quotes.
*/
public static boolean isSingleQuoted(String s) {
if (ObjectHelper.isEmpty(s)) {
return false;
}
if (s.startsWith("'") && s.endsWith("'")) {
return true;
}
return false;
}
/**
* Whether the string starts and ends with double quotes.
*
* @param s the string
* @return true if the string starts and ends with double quotes.
*/
public static boolean isDoubleQuoted(String s) {
if (ObjectHelper.isEmpty(s)) {
return false;
}
if (s.startsWith("\"") && s.endsWith("\"")) {
return true;
}
return false;
}
/**
* Encodes the text into safe XML by replacing < > and & with XML tokens
*
* @param text the text
* @return the encoded text
*/
public static String xmlEncode(final String text) {
if (text == null) {
return "";
}
// must replace amp first, so we dont replace < to amp later
return text.replace("&", "&")
.replace("\"", """)
.replace("'", "'")
.replace("<", "<")
.replace(">", ">");
}
/**
* Decodes the text into safe XML by replacing XML tokens with character values
*
* @param text the text
* @return the encoded text
*/
public static String xmlDecode(final String text) {
if (text == null) {
return "";
}
// must replace amp first, so we dont replace < to amp later
return text.replace("&", "&")
.replace(""", "\"")
.replace("'", "'")
.replace("<", "<")
.replace(">", ">");
}
/**
* Determines if the string has at least one letter in upper case
*
* @param text the text
* @return true if at least one letter is upper case, false otherwise
*/
public static boolean hasUpperCase(String text) {
if (text == null) {
return false;
}
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if (Character.isUpperCase(ch)) {
return true;
}
}
return false;
}
/**
* Determines if the string is a fully qualified class name
*/
public static boolean isClassName(String text) {
if (text != null) {
int lastIndexOf = text.lastIndexOf('.');
if (lastIndexOf <= 0) {
return false;
}
return Character.isUpperCase(text.charAt(lastIndexOf + 1));
}
return false;
}
/**
* Does the expression have the language start token?
*
* @param expression the expression
* @param language the name of the language, such as simple
* @return true if the expression contains the start token, false otherwise
*/
public static boolean hasStartToken(String expression, String language) {
if (expression == null) {
return false;
}
// for the simple language, the expression start token could be "${"
if ("simple".equalsIgnoreCase(language) && expression.contains("${")) {
return true;
}
if (language != null && expression.contains("$" + language + "{")) {
return true;
}
return false;
}
/**
* Replaces the first from token in the given input string.
*
* This implementation is not recursive, not does it check for tokens in the replacement string. If from or to is
* null, then the input string is returned as-is
*
* @param input the input string
* @param from the from string
* @param to the replacement string
* @return the replaced string, or the input string if no replacement was needed
* @throws IllegalArgumentException if the input arguments is invalid
*/
public static String replaceFirst(String input, String from, String to) {
if (from == null || to == null) {
return input;
}
int pos = input.indexOf(from);
if (pos != -1) {
int len = from.length();
return input.substring(0, pos) + to + input.substring(pos + len);
} else {
return input;
}
}
/**
* Creates a JSON tuple with the given name/value pair.
*
* @param name the name
* @param value the value
* @param isMap whether the tuple should be map
* @return the json
*/
public static String toJson(String name, String value, boolean isMap) {
if (isMap) {
return "{ " + StringQuoteHelper.doubleQuote(name) + ": " + StringQuoteHelper.doubleQuote(value) + " }";
} else {
return StringQuoteHelper.doubleQuote(name) + ": " + StringQuoteHelper.doubleQuote(value);
}
}
/**
* Asserts whether the string is not empty.
*
* @param value the string to test
* @param name the key that resolved the value
* @return the passed {@code value} as is
* @throws IllegalArgumentException is thrown if assertion fails
*/
public static String notEmpty(String value, String name) {
if (ObjectHelper.isEmpty(value)) {
throw new IllegalArgumentException(name + " must be specified and not empty");
}
return value;
}
/**
* Asserts whether the string is not empty.
*
* @param value the string to test
* @param on additional description to indicate where this problem occurred (appended as
* toString())
* @param name the key that resolved the value
* @return the passed {@code value} as is
* @throws IllegalArgumentException is thrown if assertion fails
*/
public static String notEmpty(String value, String name, Object on) {
if (on == null) {
ObjectHelper.notNull(value, name);
} else if (ObjectHelper.isEmpty(value)) {
throw new IllegalArgumentException(name + " must be specified and not empty on: " + on);
}
return value;
}
public static String[] splitOnCharacter(String value, String needle, int count) {
String[] rc = new String[count];
rc[0] = value;
for (int i = 1; i < count; i++) {
String v = rc[i - 1];
int p = v.indexOf(needle);
if (p < 0) {
return rc;
}
rc[i - 1] = v.substring(0, p);
rc[i] = v.substring(p + 1);
}
return rc;
}
public static Iterator splitOnCharacterAsIterator(String value, char needle, int count) {
// skip leading and trailing needles
int end = value.length() - 1;
boolean skipStart = value.charAt(0) == needle;
boolean skipEnd = value.charAt(end) == needle;
if (skipStart && skipEnd) {
value = value.substring(1, end);
count = count - 2;
} else if (skipStart) {
value = value.substring(1);
count = count - 1;
} else if (skipEnd) {
value = value.substring(0, end);
count = count - 1;
}
final int size = count;
final String text = value;
return new Iterator<>() {
int i;
int pos;
@Override
public boolean hasNext() {
return i < size;
}
@Override
public String next() {
if (i == size) {
throw new NoSuchElementException();
}
String answer;
int end = text.indexOf(needle, pos);
if (end != -1) {
answer = text.substring(pos, end);
pos = end + 1;
} else {
answer = text.substring(pos);
// no more data
i = size;
}
return answer;
}
};
}
public static List splitOnCharacterAsList(String value, char needle, int count) {
// skip leading and trailing needles
int end = value.length() - 1;
boolean skipStart = value.charAt(0) == needle;
boolean skipEnd = value.charAt(end) == needle;
if (skipStart && skipEnd) {
value = value.substring(1, end);
count = count - 2;
} else if (skipStart) {
value = value.substring(1);
count = count - 1;
} else if (skipEnd) {
value = value.substring(0, end);
count = count - 1;
}
List rc = new ArrayList<>(count);
int pos = 0;
for (int i = 0; i < count; i++) {
end = value.indexOf(needle, pos);
if (end != -1) {
String part = value.substring(pos, end);
pos = end + 1;
rc.add(part);
} else {
rc.add(value.substring(pos));
break;
}
}
return rc;
}
/**
* Removes any starting characters on the given text which match the given character
*
* @param text the string
* @param ch the initial characters to remove
* @return either the original string or the new substring
*/
public static String removeStartingCharacters(String text, char ch) {
int idx = 0;
while (text.charAt(idx) == ch) {
idx++;
}
if (idx > 0) {
return text.substring(idx);
}
return text;
}
/**
* Capitalize the string (upper case first character)
*
* @param text the string
* @return the string capitalized (upper case first character)
*/
public static String capitalize(String text) {
return capitalize(text, false);
}
/**
* Capitalize the string (upper case first character)
*
* @param text the string
* @param dashToCamelCase whether to also convert dash format into camel case (hello-great-world ->
* helloGreatWorld)
* @return the string capitalized (upper case first character)
*/
public static String capitalize(final String text, boolean dashToCamelCase) {
String ret = text;
if (dashToCamelCase) {
ret = dashToCamelCase(text);
}
return doCapitalize(ret);
}
private static String doCapitalize(String ret) {
if (ret == null) {
return null;
}
final char[] chars = ret.toCharArray();
// We are OK with the limitations of Character.toUpperCase. The symbols and ideographs
// for which it does not return the capitalized value should not be used here (this is
// mostly used to capitalize setters/getters)
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
}
/**
* De-capitalize the string (lower case first character)
*
* @param text the string
* @return the string decapitalized (lower case first character)
*/
public static String decapitalize(final String text) {
if (text == null) {
return null;
}
final char[] chars = text.toCharArray();
// We are OK with the limitations of Character.toLowerCase. The symbols and ideographs
// for which it does not return the lower case value should not be used here (this isap
// mostly used to convert part of setters/getters to properties)
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
/**
* Whether the string contains dashes or not
*
* @param text the string to check
* @return true if it contains dashes or false otherwise
*/
public static boolean isDashed(String text) {
return !text.isEmpty() && text.indexOf('-') != -1;
}
/**
* Converts the string from dash format into camel case (hello-great-world -> helloGreatWorld)
*
* @param text the string
* @return the string camel cased
*/
public static String dashToCamelCase(final String text) {
if (text == null) {
return null;
}
if (!isDashed(text)) {
return text;
}
// there is at least 1 dash so the capacity can be shorter
int length = text.length();
StringBuilder sb = new StringBuilder(length - 1);
boolean upper = false;
for (int i = 0; i < length; i++) {
char c = text.charAt(i);
if (c == '-') {
upper = true;
} else {
if (upper) {
c = Character.toUpperCase(c);
upper = false;
}
sb.append(c);
}
}
return sb.toString();
}
/**
* Converts the string from dash format into camel case, using the special for skip mode where we should keep text
* inside quotes or keys as-is. Where an input such as "camel.component.rabbitmq.args[queue.x-queue-type]" is
* transformed into camel.component.rabbitmq.args[queue.xQueueType]
*
* @param text the string
* @return the string camel cased
*/
private static String skippingDashToCamelCase(final String text) {
if (text == null) {
return null;
}
if (!isDashed(text)) {
return text;
}
// there is at least 1 dash so the capacity can be shorter
int length = text.length();
StringBuilder sb = new StringBuilder(length - 1);
boolean upper = false;
int singleQuotes = 0;
int doubleQuotes = 0;
boolean skip = false;
for (int i = 0; i < length; i++) {
char c = text.charAt(i);
if (c == ']') {
skip = false;
} else if (c == '[') {
skip = true;
} else if (c == '\'') {
singleQuotes++;
} else if (c == '"') {
doubleQuotes++;
}
if (singleQuotes > 0) {
skip = singleQuotes % 2 == 1;
}
if (doubleQuotes > 0) {
skip = doubleQuotes % 2 == 1;
}
if (skip) {
sb.append(c);
continue;
}
if (c == '-') {
upper = true;
} else {
if (upper) {
c = Character.toUpperCase(c);
}
sb.append(c);
upper = false;
}
}
return sb.toString();
}
/**
* Converts the string from dash format into camel case (hello-great-world -> helloGreatWorld)
*
* @param text the string
* @param skipQuotedOrKeyed flag to skip converting within a quoted or keyed text
* @return the string camel cased
*/
public static String dashToCamelCase(final String text, boolean skipQuotedOrKeyed) {
if (!skipQuotedOrKeyed) {
return dashToCamelCase(text);
} else {
return skippingDashToCamelCase(text);
}
}
/**
* Returns the string after the given token
*
* @param text the text
* @param after the token
* @return the text after the token, or null if text does not contain the token
*/
public static String after(String text, String after) {
if (text == null) {
return null;
}
int pos = text.indexOf(after);
if (pos == -1) {
return null;
}
return text.substring(pos + after.length());
}
/**
* Returns the string after the given token or the default value
*
* @param text the text
* @param after the token
* @param defaultValue the value to return if text does not contain the token
* @return the text after the token, or the supplied defaultValue if text does not contain the token
*/
public static String after(String text, String after, String defaultValue) {
String answer = after(text, after);
return answer != null ? answer : defaultValue;
}
/**
* Returns an object after the given token
*
* @param text the text
* @param after the token
* @param mapper a mapping function to convert the string after the token to type T
* @return an Optional describing the result of applying a mapping function to the text after the token.
*/
public static Optional after(String text, String after, Function mapper) {
String result = after(text, after);
if (result == null) {
return Optional.empty();
} else {
return Optional.ofNullable(mapper.apply(result));
}
}
/**
* Returns the string after the last occurrence of the given token
*
* @param text the text
* @param after the token
* @return the text after the token, or null if text does not contain the token
*/
public static String afterLast(String text, String after) {
if (text == null) {
return null;
}
int pos = text.lastIndexOf(after);
if (pos == -1) {
return null;
}
return text.substring(pos + after.length());
}
/**
* Returns the string after the last occurrence of the given token, or the default value
*
* @param text the text
* @param after the token
* @param defaultValue the value to return if text does not contain the token
* @return the text after the token, or the supplied defaultValue if text does not contain the token
*/
public static String afterLast(String text, String after, String defaultValue) {
String answer = afterLast(text, after);
return answer != null ? answer : defaultValue;
}
/**
* Returns the string before the given token
*
* @param text the text
* @param before the token
* @return the text before the token, or null if text does not contain the token
*/
public static String before(String text, String before) {
if (text == null) {
return null;
}
int pos = text.indexOf(before);
return pos == -1 ? null : text.substring(0, pos);
}
/**
* Returns the string before the given token, or the default value
*
* @param text the text
* @param before the token
* @param defaultValue the value to return if text does not contain the token
* @return the text before the token, or the supplied defaultValue if text does not contain the token
*/
public static String before(String text, String before, String defaultValue) {
if (text == null) {
return defaultValue;
}
int pos = text.indexOf(before);
return pos == -1 ? defaultValue : text.substring(0, pos);
}
/**
* Returns the string before the given token or the default value
*
* @param text the text
* @param before the token
* @param defaultValue the value to return if the text does not contain the token
* @return the text before the token, or the supplied defaultValue if the text does not contain the
* token
*/
public static String before(String text, char before, String defaultValue) {
if (text == null) {
return defaultValue;
}
int pos = text.indexOf(before);
return pos == -1 ? defaultValue : text.substring(0, pos);
}
/**
* Returns an object before the given token
*
* @param text the text
* @param before the token
* @param mapper a mapping function to convert the string before the token to type T
* @return an Optional describing the result of applying a mapping function to the text before the token.
*/
public static Optional before(String text, String before, Function mapper) {
String result = before(text, before);
if (result == null) {
return Optional.empty();
} else {
return Optional.ofNullable(mapper.apply(result));
}
}
/**
* Returns the string before the last occurrence of the given token
*
* @param text the text
* @param before the token
* @return the text before the token, or null if the text does not contain the token
*/
public static String beforeLast(String text, String before) {
if (text == null) {
return null;
}
int pos = text.lastIndexOf(before);
return pos == -1 ? null : text.substring(0, pos);
}
/**
* Returns the string before the last occurrence of the given token, or the default value
*
* @param text the text
* @param before the token
* @param defaultValue the value to return if the text does not contain the token
* @return the text before the token, or the supplied defaultValue if the text does not contain the
* token
*/
public static String beforeLast(String text, String before, String defaultValue) {
String answer = beforeLast(text, before);
return answer != null ? answer : defaultValue;
}
/**
* Returns the string between the given tokens
*
* @param text the text
* @param after the before token
* @param before the after token
* @return the text between the tokens, or null if the text does not contain the tokens
*/
public static String between(final String text, String after, String before) {
String ret = after(text, after);
if (ret == null) {
return null;
}
return before(ret, before);
}
/**
* Returns an object between the given token
*
* @param text the text
* @param after the before token
* @param before the after token
* @param mapper a mapping function to convert the string between the token to type T
* @return an Optional describing the result of applying a mapping function to the text between the token.
*/
public static Optional between(String text, String after, String before, Function mapper) {
String result = between(text, after, before);
if (result == null) {
return Optional.empty();
} else {
return Optional.ofNullable(mapper.apply(result));
}
}
/**
* Returns the substring between the given head and tail
*
* @param text the text
* @param head the head of the substring
* @param tail the tail of the substring
* @return the substring between the given head and tail
*/
public static String between(String text, int head, int tail) {
int len = text.length();
if (head > 0) {
if (head <= len) {
text = text.substring(head);
} else {
text = "";
}
len = text.length();
}
if (tail > 0) {
if (tail <= len) {
text = text.substring(0, len - tail);
} else {
text = "";
}
}
return text;
}
/**
* Returns the string between the most outer pair of tokens
*
* The number of token pairs must be even, e.g., there must be same number of before and after tokens, otherwise
* null is returned
*
* This implementation skips matching when the text is either single or double-quoted. For example:
* ${body.matches("foo('bar')") Will not match the parenthesis from the quoted text.
*
* @param text the text
* @param after the before token
* @param before the after token
* @return the text between the outer most tokens, or null if text does not contain the tokens
*/
public static String betweenOuterPair(String text, char before, char after) {
if (text == null) {
return null;
}
int pos = -1;
int pos2 = -1;
int count = 0;
int count2 = 0;
boolean singleQuoted = false;
boolean doubleQuoted = false;
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if (!doubleQuoted && ch == '\'') {
singleQuoted = !singleQuoted;
} else if (!singleQuoted && ch == '\"') {
doubleQuoted = !doubleQuoted;
}
if (singleQuoted || doubleQuoted) {
continue;
}
if (ch == before) {
count++;
} else if (ch == after) {
count2++;
}
if (ch == before && pos == -1) {
pos = i;
} else if (ch == after) {
pos2 = i;
}
}
if (pos == -1 || pos2 == -1) {
return null;
}
// must be even paris
if (count != count2) {
return null;
}
return text.substring(pos + 1, pos2);
}
/**
* Returns an object between the most outer pair of tokens
*
* @param text the text
* @param after the before token
* @param before the after token
* @param mapper a mapping function to convert the string between the most outer pair of tokens to type T
* @return an Optional describing the result of applying a mapping function to the text between the most
* outer pair of tokens.
*/
public static Optional betweenOuterPair(String text, char before, char after, Function mapper) {
String result = betweenOuterPair(text, before, after);
if (result == null) {
return Optional.empty();
} else {
return Optional.ofNullable(mapper.apply(result));
}
}
/**
* Returns true if the given name is a valid java identifier
*/
public static boolean isJavaIdentifier(String name) {
if (name == null) {
return false;
}
int size = name.length();
if (size < 1) {
return false;
}
if (Character.isJavaIdentifierStart(name.charAt(0))) {
for (int i = 1; i < size; i++) {
if (!Character.isJavaIdentifierPart(name.charAt(i))) {
return false;
}
}
return true;
}
return false;
}
/**
* Cleans the string to a pure Java identifier so we can use it for loading class names.
*
* Especially from Spring DSL people can have \n \t or other characters that otherwise would result in
* ClassNotFoundException
*
* @param name the class name
* @return normalized class name that can be load by a class loader.
*/
public static String normalizeClassName(String name) {
StringBuilder sb = new StringBuilder(name.length());
for (char ch : name.toCharArray()) {
if (ch == '.' || ch == '[' || ch == ']' || ch == '-' || Character.isJavaIdentifierPart(ch)) {
sb.append(ch);
}
}
return sb.toString();
}
/**
* Compares old and new text content and report back which lines are changed
*
* @param oldText the old text
* @param newText the new text
* @return a list of line numbers that are changed in the new text
*/
public static List changedLines(String oldText, String newText) {
if (oldText == null || oldText.equals(newText)) {
return Collections.emptyList();
}
List changed = new ArrayList<>();
String[] oldLines = oldText.split("\n");
String[] newLines = newText.split("\n");
for (int i = 0; i < newLines.length; i++) {
String newLine = newLines[i];
String oldLine = i < oldLines.length ? oldLines[i] : null;
if (oldLine == null) {
changed.add(i);
} else if (!newLine.equals(oldLine)) {
changed.add(i);
}
}
return changed;
}
/**
* Removes the leading and trailing whitespace and if the resulting string is empty returns {@code null}. Examples:
*
* Examples:
*
*
* trimToNull("abc") -> "abc"
* trimToNull(" abc") -> "abc"
* trimToNull(" abc ") -> "abc"
* trimToNull(" ") -> null
* trimToNull("") -> null
*
*
*
*/
public static String trimToNull(final String given) {
if (given == null) {
return null;
}
final String trimmed = given.trim();
if (trimmed.isEmpty()) {
return null;
}
return trimmed;
}
/**
* Checks if the src string contains what
*
* @param src is the source string to be checked
* @param what is the string which will be looked up in the src argument
* @return true/false
*/
public static boolean containsIgnoreCase(String src, String what) {
if (src == null || what == null) {
return false;
}
final int length = what.length();
if (length == 0) {
return true; // Empty string is contained
}
final char firstLo = Character.toLowerCase(what.charAt(0));
final char firstUp = Character.toUpperCase(what.charAt(0));
for (int i = src.length() - length; i >= 0; i--) {
// Quick check before calling the more expensive regionMatches() method:
final char ch = src.charAt(i);
if (ch != firstLo && ch != firstUp) {
continue;
}
if (src.regionMatches(true, i, what, 0, length)) {
return true;
}
}
return false;
}
/**
* Outputs the bytes in human-readable format in units of KB,MB,GB etc.
*
* @param locale The locale to apply during formatting. If l is {@code null} then no localization is applied.
* @param bytes number of bytes
* @return human readable output
* @see java.lang.String#format(Locale, String, Object...)
*/
public static String humanReadableBytes(Locale locale, long bytes) {
int unit = 1024;
if (bytes < unit) {
return bytes + " B";
}
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = String.valueOf("KMGTPE".charAt(exp - 1));
return String.format(locale, "%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
/**
* Outputs the bytes in human-readable format in units of KB,MB,GB etc.
*
* The locale always used is the one returned by {@link java.util.Locale#getDefault()}.
*
* @param bytes number of bytes
* @return human readable output
* @see org.apache.camel.util.StringHelper#humanReadableBytes(Locale, long)
*/
public static String humanReadableBytes(long bytes) {
return humanReadableBytes(Locale.getDefault(), bytes);
}
/**
* Check for string pattern matching with a number of strategies in the following order:
*
* - equals - null pattern always matches - * always matches - Ant style matching - Regexp
*
* @param pattern the pattern
* @param target the string to test
* @return true if target matches the pattern
*/
public static boolean matches(String pattern, String target) {
if (Objects.equals(pattern, target)) {
return true;
}
if (Objects.isNull(pattern)) {
return true;
}
if (Objects.equals("*", pattern)) {
return true;
}
if (AntPathMatcher.INSTANCE.match(pattern, target)) {
return true;
}
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(target);
return m.matches();
}
/**
* Converts the string from camel case into dot format (helloGreatWorld -> hello.great.world)
*
* @param text the string
* @return the string dot cased
*/
public static String camelCaseToDot(String text) {
if (text == null || text.isEmpty()) {
return text;
}
text = camelCaseToDash(text);
return text.replace('-', '.');
}
/**
* Converts the string from camel case into dash format (helloGreatWorld -> hello-great-world)
*
* @param text the string
* @return the string camel cased
*/
public static String camelCaseToDash(String text) {
if (text == null || text.isEmpty()) {
return text;
}
char prev = 0;
char[] arr = text.toCharArray();
StringBuilder answer = new StringBuilder(arr.length < 13 ? 16 : arr.length + 8);
for (int i = 0; i < arr.length; i++) {
char ch = arr[i];
if (ch == '-' || ch == '_') {
answer.append("-");
} else {
if (Character.isUpperCase(ch) && prev != 0) {
char next;
if (i < arr.length - 1) {
next = arr[i + 1];
} else {
next = 0;
}
if (!Character.isUpperCase(prev) || next != 0 && Character.isLowerCase(next)) {
applyDashPrefix(prev, answer, ch);
} else {
answer.append(Character.toLowerCase(ch));
}
} else {
answer.append(Character.toLowerCase(ch));
}
}
prev = ch;
}
return answer.toString();
}
private static void applyDashPrefix(char prev, StringBuilder answer, char ch) {
if (prev != '-' && prev != '_') {
answer.append("-");
}
answer.append(Character.toLowerCase(ch));
}
/**
* Does the string start with the given prefix (ignoring the case).
*
* @param text the string
* @param prefix the prefix
*/
public static boolean startsWithIgnoreCase(String text, String prefix) {
if (text != null && prefix != null) {
return prefix.length() <= text.length() && text.regionMatches(true, 0, prefix, 0, prefix.length());
} else {
return text == null && prefix == null;
}
}
/**
* Converts the value to an enum constant value that is in the form of upper-cased with underscore.
*/
public static String asEnumConstantValue(final String value) {
if (value == null || value.isEmpty()) {
return value;
}
String ret = StringHelper.camelCaseToDash(value);
// replace double dashes
ret = ret.replaceAll("-+", "-");
// replace dash with underscore and upper case
ret = ret.replace('-', '_').toUpperCase(Locale.ENGLISH);
return ret;
}
/**
* Split the text on words, eg hello/world => becomes array with hello in index 0, and world in index 1.
*/
public static String[] splitWords(String text) {
return text.split("[\\W]+");
}
/**
* Creates a stream from the given input sequence around matches of the regex
*
* @param text the input
* @param regex the expression used to split the input
* @return the stream of strings computed by splitting the input with the given regex
*/
public static Stream splitAsStream(CharSequence text, String regex) {
if (text == null || regex == null) {
return Stream.empty();
}
return Pattern.compile(regex).splitAsStream(text);
}
/**
* Returns the occurrence of a search string in to a string.
*
* @param text the text
* @param search the string to search
* @return an integer reporting the occurrences of the searched string in to the text
*/
public static int countOccurrence(String text, String search) {
int lastIndex = 0;
int count = 0;
while (lastIndex != -1) {
lastIndex = text.indexOf(search, lastIndex);
if (lastIndex != -1) {
count++;
lastIndex += search.length();
}
}
return count;
}
/**
* Replaces a string in to a text starting from his second occurrence.
*
* @param text the text
* @param search the string to search
* @param replacement the replacement for the string
* @return the string with the replacement
*/
public static String replaceFromSecondOccurrence(String text, String search, String replacement) {
int index = text.indexOf(search);
boolean replace = false;
while (index != -1) {
String tempString = text.substring(index);
if (replace) {
tempString = tempString.replaceFirst(search, replacement);
text = text.substring(0, index) + tempString;
replace = false;
} else {
replace = true;
}
index = text.indexOf(search, index + 1);
}
return text;
}
/**
* Pad the string with leading spaces
*
* @param level level (2 blanks per level)
*/
public static String padString(int level) {
return padString(level, 2);
}
/**
* Pad the string with leading spaces
*
* @param level level
* @param blanks number of blanks per level
*/
public static String padString(int level, int blanks) {
if (level == 0) {
return "";
} else {
return " ".repeat(level * blanks);
}
}
/**
* Fills the string with repeating chars
*
* @param ch the char
* @param count number of chars
*/
public static String fillChars(char ch, int count) {
if (count <= 0) {
return "";
} else {
return Character.toString(ch).repeat(count);
}
}
public static boolean isDigit(String s) {
for (char ch : s.toCharArray()) {
if (!Character.isDigit(ch)) {
return false;
}
}
return true;
}
public static String bytesToHex(byte[] hash) {
StringBuilder sb = new StringBuilder(2 * hash.length);
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy