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

com.aspectran.utils.StringUtils Maven / Gradle / Ivy

There is a newer version: 8.1.5
Show newest version
/*
 * Copyright (c) 2008-2024 The Aspectran Project
 *
 * Licensed 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 com.aspectran.utils;

import com.aspectran.utils.annotation.jsr305.NonNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;

/**
 * Static utility methods pertaining to {@code String} or {@code CharSequence} instances.
 */
public abstract class StringUtils {

    /** Constant for an empty {@link String}. */
    public static final String EMPTY = "";

    /** Constant for an empty {@link String} array. */
    private static final String[] EMPTY_STRING_ARRAY = {};

    /**
     * Returns {@code true} if the given string is null or is the empty string.
     * @param str a string reference to check
     * @return {@code true} if the string is null or is the empty string
     */
    public static boolean isEmpty(String str) {
        return (str == null || str.isEmpty());
    }

    /**
     * Returns the given string if it is non-null; the empty string otherwise.
     * @param str the string to test and possibly return
     * @return {@code string} itself if it is non-null; {@code ""} if it is null
     */
    public static String nullToEmpty(String str) {
        return (str != null ? str : EMPTY);
    }

    /**
     * Returns the given string if it is nonempty; {@code null} otherwise.
     * @param str the string to test and possibly return
     * @return {@code string} itself if it is nonempty; {@code null} if it is empty or null
     */
    public static String emptyToNull(String str) {
        return (str == null || str.isEmpty() ? null : str);
    }

    /**
     * Check that the given {@code CharSequence} is neither {@code null} nor of length 0.
     * 

Note: this method returns {@code true} for a {@code CharSequence} * that purely consists of whitespace.

*
     * StringUtils.hasLength(null) = false
     * StringUtils.hasLength("") = false
     * StringUtils.hasLength(" ") = true
     * StringUtils.hasLength("Hello") = true
     * 
* @param chars the {@code CharSequence} to check (may be {@code null}) * @return {@code true} if the {@code CharSequence} is not {@code null} and has length * @see #hasLength(String) * @see #hasText(CharSequence) */ public static boolean hasLength(CharSequence chars) { return (chars != null && !chars.isEmpty()); } /** * Check that the given {@code String} is neither {@code null} nor of length 0. *

Note: this method returns {@code true} for a {@code String} that * purely consists of whitespace.

* @param str the {@code String} to check (may be {@code null}) * @return {@code true} if the {@code String} is not {@code null} and has length * @see #hasLength(CharSequence) * @see #hasText(String) */ public static boolean hasLength(String str) { return (str != null && !str.isEmpty()); } /** * Check whether the given {@code CharSequence} contains actual text. *

More specifically, this method returns {@code true} if the * {@code CharSequence} is not {@code null}, its length is greater than * 0, and it contains at least one non-whitespace character.

*
     * StringUtils.hasText(null) = false
     * StringUtils.hasText("") = false
     * StringUtils.hasText(" ") = false
     * StringUtils.hasText("12345") = true
     * StringUtils.hasText(" 12345 ") = true
     * 
* @param chars the {@code CharSequence} to check (may be {@code null}) * @return {@code true} if the {@code CharSequence} is not {@code null}, * its length is greater than 0, and it does not contain whitespace only * @see #hasLength(String) * @see #hasText(CharSequence) * @see Character#isWhitespace */ public static boolean hasText(CharSequence chars) { return (chars != null && !chars.isEmpty() && containsText(chars)); } /** * Check whether the given {@code String} contains actual text. *

More specifically, this method returns {@code true} if the * {@code String} is not {@code null}, its length is greater than 0, * and it contains at least one non-whitespace character.

* @param str the {@code String} to check (may be {@code null}) * @return {@code true} if the {@code String} is not {@code null}, its * length is greater than 0, and it does not contain whitespace only * @see #hasText(CharSequence) * @see #hasLength(String) * @see Character#isWhitespace */ public static boolean hasText(String str) { return (str != null && !str.isEmpty() && containsText(str)); } private static boolean containsText(@NonNull CharSequence chars) { int strLen = chars.length(); for (int i = 0; i < strLen; i++) { if (!Character.isWhitespace(chars.charAt(i))) { return true; } } return false; } /** * Check whether the given {@code CharSequence} contains any whitespace characters. * @param chars the {@code CharSequence} to check (maybe {@code null}) * @return {@code true} if the {@code CharSequence} is not empty and * contains at least 1 whitespace character * @see Character#isWhitespace */ public static boolean containsWhitespace(CharSequence chars) { if (!hasLength(chars)) { return false; } int strLen = chars.length(); for (int i = 0; i < strLen; i++) { if (Character.isWhitespace(chars.charAt(i))) { return true; } } return false; } /** * Check whether the given {@code String} contains any whitespace characters. * @param str the {@code String} to check (may be {@code null}) * @return {@code true} if the {@code String} is not empty and * contains at least 1 whitespace character * @see #containsWhitespace(CharSequence) */ public static boolean containsWhitespace(String str) { return containsWhitespace((CharSequence)str); } /** * Trim leading and trailing whitespace from the given {@code String}. * @param str the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder buf = new StringBuilder(str); while (!buf.isEmpty() && Character.isWhitespace(buf.charAt(0))) { buf.deleteCharAt(0); } while (!buf.isEmpty() && Character.isWhitespace(buf.charAt(buf.length() - 1))) { buf.deleteCharAt(buf.length() - 1); } return buf.toString(); } /** * Trim all whitespace from the given {@code String}: * leading, trailing, and in between characters. * @param str the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimAllWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder buf = new StringBuilder(str); int index = 0; while (buf.length() > index) { if (Character.isWhitespace(buf.charAt(index))) { buf.deleteCharAt(index); } else { index++; } } return buf.toString(); } /** * Trim leading whitespace from the given {@code String}. * @param str the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimLeadingWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder buf = new StringBuilder(str); while (!buf.isEmpty() && Character.isWhitespace(buf.charAt(0))) { buf.deleteCharAt(0); } return buf.toString(); } /** * Trim trailing whitespace from the given {@code String}. * @param str the {@code String} to check * @return the trimmed {@code String} * @see java.lang.Character#isWhitespace */ public static String trimTrailingWhitespace(String str) { if (!hasLength(str)) { return str; } StringBuilder buf = new StringBuilder(str); while (!buf.isEmpty() && Character.isWhitespace(buf.charAt(buf.length() - 1))) { buf.deleteCharAt(buf.length() - 1); } return buf.toString(); } /** * Trim all occurrences of the supplied leading character from the given {@code String}. * @param str the {@code String} to check * @param leadingChar the leading character to be trimmed * @return the trimmed {@code String} */ public static String trimLeadingCharacter(String str, char leadingChar) { if (!hasLength(str)) { return str; } StringBuilder buf = new StringBuilder(str); while (!buf.isEmpty() && buf.charAt(0) == leadingChar) { buf.deleteCharAt(0); } return buf.toString(); } /** * Trim all occurrences of the supplied trailing character from the given {@code String}. * @param str the {@code String} to check * @param trailingChar the trailing character to be trimmed * @return the trimmed {@code String} */ public static String trimTrailingCharacter(String str, char trailingChar) { if (!hasLength(str)) { return str; } StringBuilder buf = new StringBuilder(str); while (!buf.isEmpty() && buf.charAt(buf.length() - 1) == trailingChar) { buf.deleteCharAt(buf.length() - 1); } return buf.toString(); } /** * Test if the given {@code String} starts with the specified prefix, * ignoring upper/lower case. * @param str the {@code String} to check * @param prefix the prefix to look for * @return {@code true} if the {@code String} starts with the prefix, * case-insensitive, or both {@code null} * @see java.lang.String#startsWith */ public static boolean startsWithIgnoreCase(String str, String prefix) { return (str != null && prefix != null && str.length() >= prefix.length() && str.regionMatches(true, 0, prefix, 0, prefix.length())); } /** * Test if the given {@code String} ends with the specified suffix, * ignoring upper/lower case. * @param str the {@code String} to check * @param suffix the suffix to look for * @return {@code true} if the {@code String} ends with the suffix, * case-insensitive, or both {@code null} * @see java.lang.String#endsWith */ public static boolean endsWithIgnoreCase(String str, String suffix) { return (str != null && suffix != null && str.length() >= suffix.length() && str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length())); } /** * Test if the given {@code String} starts with the specified prefix character. * @param str the {@code String} to check * @param prefix the prefix character to look for * @return true if the string starts with the specified prefix; otherwise false * @see java.lang.String#startsWith */ public static boolean startsWith(String str, char prefix) { return (str != null && !str.isEmpty() && (str.charAt(0) == prefix)); } /** * Test if the given {@code String} ends with the specified prefix character. * @param str the {@code String} to check * @param suffix the prefix character to look for * @return true if the string ends with the specified suffix; otherwise false * @see java.lang.String#endsWith */ public static boolean endsWith(String str, char suffix) { return (str != null && !str.isEmpty() && (str.charAt(str.length() - 1) == suffix)); } /** * Replace all occurrences of a substring within a string with another string. * @param str {@code String} to examine * @param search {@code String} to replace * @param replacement {@code String} to insert * @return a {@code String} with the replacements */ public static String replace(String str, String search, String replacement) { if (str == null || search == null || replacement == null) { return str; } StringBuilder sb = new StringBuilder(); int searchLen = search.length(); int stringLen = str.length(); int oldIndex = 0; int index; while ((index = str.indexOf(search, oldIndex)) >= 0) { sb.append(str, oldIndex, index); sb.append(replacement); oldIndex = index + searchLen; } if (oldIndex < stringLen) { sb.append(str, oldIndex, stringLen); } return sb.toString(); } /** * Replace all occurrences of a substring within a string with another string. * @param str {@code String} to examine * @param searchList {@code String} array to replace * @param replacementList {@code String} array to insert * @return a {@code String} with the replacements */ public static String replace(String str, String[] searchList, String[] replacementList) { if (str == null || searchList == null || replacementList == null) { return str; } StringBuilder sb = new StringBuilder(str); int loop = Math.min(searchList.length, replacementList.length); int start = 0; int end; int searchLen; int replaceLen; for (int i = 0; i < loop; i++) { if (searchList[i] == null || replacementList[i] == null) { continue; } searchLen = searchList[i].length(); replaceLen = replacementList[i].length(); while (true) { if (sb.isEmpty()) { break; } start = sb.indexOf(searchList[i], start + replaceLen); if (start == -1) { break; } end = start + searchLen; sb.replace(start, end, replacementList[i]); } } return sb.toString(); } /** * Replace last occurrence of a string. * @param str {@code String} to examine * @param searchStr {@code String} to replace * @param replacement {@code String} to insert * @return a {@code String} with the replacements */ @NonNull public static String replaceLast(@NonNull String str, @NonNull String searchStr, @NonNull String replacement) { int pos = str.lastIndexOf(searchStr); if (pos > -1) { return str.substring(0, pos) + replacement + str.substring(pos + searchStr.length()); } else { return str; } } /** * Returns an array of strings separated by the delimiter string. * @param str the string to be separated * @param delim the delimiter * @return an array, containing the splitted strings */ public static String[] split(String str, String delim) { if (isEmpty(str)) { return EMPTY_STRING_ARRAY; } int cnt = search(str, delim); String[] item = new String[cnt + 1]; if (cnt == 0) { item[0] = str; return item; } int idx = 0; int pos1 = 0; int pos2 = str.indexOf(delim); int delimLen = delim.length(); while (pos2 >= 0) { item[idx++] = (pos1 > pos2 - 1) ? EMPTY : str.substring(pos1, pos2); pos1 = pos2 + delimLen; pos2 = str.indexOf(delim, pos1); } if (pos1 < str.length()) { item[idx] = str.substring(pos1); } if (item[cnt] == null) { item[cnt] = EMPTY; } return item; } /** * Returns an array of strings separated by the delimiter string. * @param str the string to be separated * @param delim the delimiter * @param size the size of the array * @return an array, containing the splitted strings */ @NonNull public static String[] split(String str, String delim, int size) { String[] arr1 = new String[size]; String[] arr2 = split(str, delim); for (int i = 0; i < arr1.length; i++) { if (i < arr2.length) { arr1[i] = arr2[i]; } else { arr1[i] = EMPTY; } } return arr1; } /** * Returns an array of strings separated by the delimiter string. * @param str the string to be separated * @param delim the delimiter * @return an array, containing the splitted strings */ public static String[] split(String str, char delim) { if (isEmpty(str)) { return EMPTY_STRING_ARRAY; } int cnt = search(str, delim); String[] item = new String[cnt + 1]; if (cnt == 0) { item[0] = str; return item; } int idx = 0; int pos1 = 0; int pos2 = str.indexOf(delim); while (pos2 >= 0) { item[idx++] = (pos1 > pos2 - 1) ? EMPTY : str.substring(pos1, pos2); pos1 = pos2 + 1; pos2 = str.indexOf(delim, pos1); } if (pos1 < str.length()) { item[idx] = str.substring(pos1); } if (item[cnt] == null) { item[cnt] = EMPTY; } return item; } /** * Returns an array of strings separated by the delimiter string. * @param str the string to be separated * @param delim the delimiter * @param size the size of the array * @return an array, containing the splitted strings */ @NonNull public static String[] split(String str, char delim, int size) { String[] arr1 = new String[size]; String[] arr2 = split(str, delim); for (int i = 0; i < arr1.length; i++) { if (i < arr2.length) { arr1[i] = arr2[i]; } else { arr1[i] = EMPTY; } } return arr1; } /** * Returns the number of times the specified string was found * in the target string, or 0 if there is no specified string. * @param str the target string * @param searchStr the string to find * @return the number of times the specified string was found */ public static int search(@NonNull String str, @NonNull String searchStr) { int strLen = str.length(); int keywLen = searchStr.length(); int pos = 0; int cnt = 0; if (keywLen == 0) { return 0; } while ((pos = str.indexOf(searchStr, pos)) != -1) { pos += keywLen; cnt++; if (pos >= strLen) { break; } } return cnt; } /** * Returns the number of times the specified string was found * in the target string, or 0 if there is no specified string. * When searching for the specified string, it is not case-sensitive. * @param str the target string * @param searchStr the string to find * @return the number of times the specified string was found */ public static int searchIgnoreCase(@NonNull String str, @NonNull String searchStr) { return search(str.toLowerCase(), searchStr.toLowerCase()); } /** * Returns the number of times the specified character was found * in the target string, or 0 if there is no specified character. * @param chars the target string * @param c the character to find * @return the number of times the specified character was found */ public static int search(@NonNull CharSequence chars, char c) { int count = 0; for (int i = 0; i < chars.length(); i++) { if (chars.charAt(i) == c) { count++; } } return count; } /** * Returns the number of times the specified character was found * in the target string, or 0 if there is no specified character. * When searching for the specified character, it is not case-sensitive. * @param chars the target string * @param searchChar the character to find * @return the number of times the specified character was found */ public static int searchIgnoreCase(@NonNull CharSequence chars, char searchChar) { int count = 0; char cl = Character.toLowerCase(searchChar); for (int i = 0; i < chars.length(); i++) { if (Character.toLowerCase(chars.charAt(i)) == cl) { count++; } } return count; } /** * Tokenize the given {@code String} into a String array via a StringTokenizer. * @param str the {@code String} to tokenize * @param delimiters the delimiter characters * @return an array of the tokens */ public static String[] tokenize(String str, String delimiters) { return tokenize(str, delimiters, false); } /** * Tokenize the given {@code String} into a {@code String} array via a {@code StringTokenizer}. * @param str the String to tokenize * @param delimiters the delimiter characters * @param trim trim the tokens via String's trim * @return an array of the tokens */ public static String[] tokenize(String str, String delimiters, boolean trim) { if (str == null) { return EMPTY_STRING_ARRAY; } StringTokenizer st = new StringTokenizer((trim ? str.trim() : str), delimiters); List tokens = new ArrayList<>(); while (st.hasMoreTokens()) { String token = st.nextToken(); tokens.add(trim ? token.trim() : token); } return tokens.toArray(EMPTY_STRING_ARRAY); } /** * Convert a {@code String} array into a delimited {@code String} (e.g. CSV). *

Useful for {@code toString()} implementations.

* @param arr the array to display * @param delim the delimiter to use (typically a ",") * @return the delimited {@code String} */ public static String toDelimitedString(Object[] arr, String delim) { if (arr == null || arr.length == 0) { return EMPTY; } if (arr.length == 1) { return (arr[0] == null ? EMPTY : arr[0].toString()); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { if (i > 0) { sb.append(delim); } sb.append(arr[i]); } return sb.toString(); } /** * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV). *

Useful for {@code toString()} implementations.

* @param collection the collection * @param delim the delimiter to use (typically a ",") * @return the delimited {@code String} */ public static String toDelimitedString(Collection collection, String delim) { if (collection == null || collection.isEmpty()) { return EMPTY; } StringBuilder sb = new StringBuilder(); boolean first = true; for (Object o : collection) { if (!first) { sb.append(delim); } sb.append(o); first = false; } return sb.toString(); } /** * Convert a {@code String} array into a delimited {@code String} * by a system-dependent line separator. * @param arr the array to display * @return the delimited {@code String} */ public static String toLineDelimitedString(Object[] arr) { return toDelimitedString(arr, System.lineSeparator()); } /** * Convert a {@code Collection} into a delimited {@code String} * by a system-dependent line separator. * @param collection the collection * @return the delimited {@code String} */ public static String toLineDelimitedString(Collection collection) { return toDelimitedString(collection, System.lineSeparator()); } /** * Convert a comma delimited list (e.g., a row from a CSV file) into an * array of strings. * @param str the input {@code String} * @return an array of strings, or the empty array in case of empty input */ public static String[] splitCommaDelimitedString(String str) { return tokenize(str, ",", true); } /** * Convert a {@code String} array into a comma delimited {@code String} * (i.e., CSV). * @param arr the array to display * @return the delimited {@code String} */ public static String joinCommaDelimitedList(String[] arr) { return toDelimitedString(arr, ", "); } /** * Convert a {@code Collection} into a comma delimited {@code String} * (i.e., CSV). * @param collection the collection * @return the delimited {@code String} */ public static String joinCommaDelimitedList(Collection collection) { return toDelimitedString(collection, ", "); } /** * Copy the given {@link Collection} into a {@code String} array. *

The {@code Collection} must contain {@code String} elements only. * @param collection the {@code Collection} to copy * (potentially {@code null} or empty) * @return the resulting {@code String} array */ public static String[] toStringArray(Collection collection) { return (collection != null && !collection.isEmpty() ? collection.toArray(EMPTY_STRING_ARRAY) : EMPTY_STRING_ARRAY); } /** * Copy the given {@link Enumeration} into a {@code String} array. *

The {@code Enumeration} must contain {@code String} elements only. * @param enumeration the {@code Enumeration} to copy * (potentially {@code null} or empty) * @return the resulting {@code String} array */ public static String[] toStringArray(Enumeration enumeration) { return (enumeration != null ? toStringArray(Collections.list(enumeration)) : EMPTY_STRING_ARRAY); } /** * Returns padding using the specified delimiter repeated to a given length. * @param ch character to repeat * @param repeat number of times to repeat char, negative treated as zero * @return String with repeated character */ public static String repeat(char ch, final int repeat) { if (repeat <= 0) { return EMPTY; } char[] buf = new char[repeat]; for (int i = repeat - 1; i >= 0; i--) { buf[i] = ch; } return new String(buf); } /** * Convert byte size into human friendly format. * @param bytes the number of bytes * @return a human friendly byte size (includes units) */ public static String convertToHumanFriendlyByteSize(long bytes) { if (bytes < 1024 && bytes > -1024) { return bytes + " B"; } String minus = null; if (bytes < 0) { minus = "-"; bytes = -bytes; } int z = (63 - Long.numberOfLeadingZeros(bytes)) / 10; double d = (double)bytes / (1L << (z * 10)); String format = (d % 1.0 == 0 ? "%s%.0f %sB" : "%s%.1f %sB"); return String.format(format, nullToEmpty(minus), d, " KMGTPE".charAt(z)); } /** * Convert byte size into machine friendly format. * @param bytes the human friendly byte size (includes units) * @return a number of bytes * @throws NumberFormatException if failed parse given size */ @SuppressWarnings("fallthrough") public static long convertToMachineFriendlyByteSize(@NonNull String bytes) { double d; try { d = Double.parseDouble(bytes.replaceAll("[GMK]?B?$", EMPTY)); } catch (NumberFormatException e) { String msg = "Size must be specified as bytes (B), " + "kilobytes (KB), megabytes (MB), gigabytes (GB). " + "E.g. 1024, 1KB, 10M, 10MB, 100G, 100GB"; throw new NumberFormatException(msg + " " + e.getMessage()); } long l = Math.round(d * 1024 * 1024 * 1024L); int index = Math.max(0, bytes.length() - (bytes.endsWith("B") ? 2 : 1)); switch (bytes.charAt(index)) { default: l /= 1024; case 'K': l /= 1024; case 'M': l /= 1024; case 'G': return l; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy