All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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