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

com.landawn.abacus.util.Strings Maven / Gradle / Ivy

/*
 * Copyright (c) 2015, Haiyang Li.
 *
 * 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.landawn.abacus.util;

import static com.landawn.abacus.util.WD._BACKSLASH;
import static com.landawn.abacus.util.WD._QUOTATION_D;
import static com.landawn.abacus.util.WD._QUOTATION_S;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.RandomAccess;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.lang.model.SourceVersion;

import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.MayReturnNull;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalChar;
import com.landawn.abacus.util.stream.Stream;

/**
 * 

* Note: This class includes codes copied from Apache Commons Lang, Google Guava and other open source projects under the Apache License 2.0. * The methods copied from other libraries/frameworks/projects may be modified in this class. *

* *
*
* When to throw exception? It's designed to avoid throwing any unnecessary * exception if the contract defined by method is not broken. for example, if * user tries to reverse a {@code null} or empty String. the input String will be * returned. But exception will be thrown if try to add element to a {@code null} Object array or collection. *
*
* An empty String/Array/Collection/Map/Iterator/Iterable/InputStream/Reader will always be a preferred choice than a {@code null} for the return value of a method. *
* * * @see {@code Joiner}, {@code Splitter} * * @see com.landawn.abacus.util.N * @see com.landawn.abacus.util.Array * @see com.landawn.abacus.util.Iterables * @see com.landawn.abacus.util.Iterators * @see com.landawn.abacus.util.Maps * @see com.landawn.abacus.util.URLEncodedUtil * @see com.landawn.abacus.util.AppendableWriter * @see com.landawn.abacus.util.StringWriter */ @SuppressWarnings({ "java:S1694", "UnnecessaryUnicodeEscape" }) public abstract sealed class Strings permits Strings.StringUtil { private static final Logger LOGGER = LoggerFactory.getLogger(Strings.class); /** * String with value {@code "null"}. */ @Beta public static final String NULL_STRING = "null"; /** * * Char array with value {@code "['n', 'u', 'l', 'l']"}. */ static final char[] NULL_CHAR_ARRAY = NULL_STRING.toCharArray(); /** * The empty String {@code ""}. */ public static final String EMPTY_STRING = ""; // /** // * The empty String {@code ""}. // * @deprecated Use {@link #EMPTY_STRING} instead // */ // @Deprecated // public static final String EMPTY = EMPTY_STRING; /** * A String for a space character. * */ public static final String SPACE = WD.SPACE; /** * A String for linefeed LF ("\n"). * * @see JLF: Escape Sequences * for Character and String Literals */ public static final String LF = "\n"; /** * A String for carriage return CR ("\r"). * * @see JLF: Escape Sequences * for Character and String Literals */ public static final String CR = "\r"; /** * Carriage return followed by line feed. This is the line ending used on Windows. */ public static final String CR_LF = "\r\n"; @Beta public static final char CHAR_ZERO = (char) 0; @Beta public static final char CHAR_SPACE = WD._SPACE; @Beta public static final char CHAR_LF = LF.charAt(0); @Beta public static final char CHAR_CR = CR.charAt(0); /** * Field COMMA_SPACE (value is {@code ", "}) */ public static final String COMMA_SPACE = WD.COMMA_SPACE; /** * Value is {@code ", "} */ public static final String ELEMENT_SEPARATOR = COMMA_SPACE; static final char[] ELEMENT_SEPARATOR_CHAR_ARRAY = ELEMENT_SEPARATOR.toCharArray(); static final String TRUE = Boolean.TRUE.toString().intern(); static final char[] TRUE_CHAR_ARRAY = TRUE.toCharArray(); static final String FALSE = Boolean.FALSE.toString().intern(); static final char[] FALSE_CHAR_ARRAY = FALSE.toCharArray(); static final String BACKSLASH_ASTERISK = "*"; static final String STR_FOR_EMPTY_ARRAY = "[]"; /** * A regex pattern for recognizing blocks of whitespace characters. The * apparent convolutedness of the pattern serves the purpose of ignoring * "blocks" consisting of only a single space: the pattern is used only to * normalize whitespace, condensing "blocks" down to a single space, thus * matching the same would likely cause a great many noop replacements. */ private static final Pattern WHITESPACE_PATTERN = Pattern.compile("(?: |\\u00A0|\\s|[\\s&&[^ ]])\\s*");//NOSONAR private static final Splitter lineSplitter = Splitter.forLines(); private static final Splitter trimLineSplitter = Splitter.forLines().trimResults(); private static final Splitter omitEmptyLinesLineSplitter = Splitter.forLines().omitEmptyStrings(); private static final Splitter trimAndOmitEmptyLinesLineSplitter = Splitter.forLines().trimResults().omitEmptyStrings(); // private static final Map splitterPool = new HashMap<>(); // // private static final Map trimSplitterPool = new HashMap<>(); // // private static final Map preserveSplitterPool = new HashMap<>(); // // private static final Map trimPreserveSplitterPool = new HashMap<>(); // // static { // final List delimiters = Array.asList(" ", " ", " ", "\t", "\n", "\r", ",", ", ", ";", "; ", ":", ": ", " : ", "-", " - ", "_", " _ ", "#", // "##", " # ", "=", "==", " = ", "|", " | ", "||", " || ", "&", "&&", "@", "@@", "$", "$$", "*", "**", "+", "++"); // // for (final String delimiter : delimiters) { // splitterPool.put(delimiter, Splitter.with(delimiter).omitEmptyStrings()); // trimSplitterPool.put(delimiter, Splitter.with(delimiter).omitEmptyStrings().trimResults()); // preserveSplitterPool.put(delimiter, Splitter.with(delimiter)); // trimPreserveSplitterPool.put(delimiter, Splitter.with(delimiter).trimResults()); // // if (delimiter.length() == 1) { // final char delimiterChar = delimiter.charAt(0); // // splitterPool.put(delimiterChar, Splitter.with(delimiterChar).omitEmptyStrings()); // trimSplitterPool.put(delimiterChar, Splitter.with(delimiterChar).omitEmptyStrings().trimResults()); // preserveSplitterPool.put(delimiterChar, Splitter.with(delimiterChar)); // trimPreserveSplitterPool.put(delimiterChar, Splitter.with(delimiterChar).trimResults()); // } // } // } private static final Pattern JAVA_IDENTIFIER_PATTERN = Pattern.compile("^([a-zA-Z_$][a-zA-Z\\d_$]*)$", Pattern.UNICODE_CHARACTER_CLASS); // https://www.baeldung.com/java-email-validation-regex // https://owasp.org/www-community/OWASP_Validation_Regex_Repository // https://stackoverflow.com/questions/201323/how-can-i-validate-an-email-address-using-a-regular-expression private static final Pattern EMAIL_ADDRESS_RFC_5322_PATTERN = Pattern.compile( "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])", //NOSONAR Pattern.UNICODE_CHARACTER_CLASS); // https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url private static final Pattern URL_PATTERN = Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)", //NOSONAR Pattern.UNICODE_CHARACTER_CLASS); private static final Pattern HTTP_URL_PATTERN = Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)", //NOSONAR Pattern.UNICODE_CHARACTER_CLASS); private static final Encoder BASE64_ENCODER = java.util.Base64.getEncoder(); private static final Decoder BASE64_DECODER = java.util.Base64.getDecoder(); private static final Encoder BASE64_URL_ENCODER = java.util.Base64.getUrlEncoder(); private static final Decoder BASE64_URL_DECODER = java.util.Base64.getUrlDecoder(); private Strings() { // Utility class. } /** * Returns a new UUID String without '-'. * * @return * @see UUID#randomUUID(). */ public static String guid() { return uuid().replace("-", ""); } /** * Returns a new UUID String. * * @return * @see UUID#randomUUID(). */ public static String uuid() { return UUID.randomUUID().toString(); } /** * Converts the provided character array into a String. * * @param value The character array to be converted. It can be {@code null}. * @return A String representation of the character array. Returns {@code null} if value is {@code null}. * @see String#valueOf(char[]) * @see N#toString(Object) */ public static String valueOf(final char[] value) { return value == null ? null : String.valueOf(value); } /** * Checks if the given CharSequence is a Java keyword. * * @param cs The CharSequence to be checked. It can be {@code null} or empty. * @return {@code true} if the CharSequence is a Java keyword, {@code false} otherwise. */ public static boolean isKeyword(final CharSequence cs) { if (isEmpty(cs)) { return false; } return SourceVersion.isKeyword(cs); } /** * Checks if the given CharSequence is a valid Java identifier. * * A valid Java identifier must start with a letter, a currency character ($), or a connecting character such as underscore (_). * Identifiers cannot start with a number, and they cannot be a Java keyword or boolean literal (true or false). * * @param cs The CharSequence to be checked. It can be {@code null} or empty. * @return {@code true} if the CharSequence is a valid Java identifier, {@code false} otherwise. */ public static boolean isValidJavaIdentifier(final CharSequence cs) { if (isEmpty(cs)) { return false; } return JAVA_IDENTIFIER_PATTERN.matcher(cs).matches(); } /** * Checks if the given CharSequence is a valid email address. * * This method uses a regular expression (RFC 5322) to validate the email address. It checks for the general form of an email address * which is "local-part@domain". The local-part can contain alphanumeric characters and special characters like !, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, } and ~. * The domain part contains at least one dot (.) and can contain alphanumeric characters as well as hyphens (-). * * @param cs The CharSequence to be checked. It can be {@code null} or empty. * @return {@code true} if the CharSequence is a valid email address, {@code false} otherwise. * @see #findFirstEmailAddress(CharSequence) * @see #findAllEmailAddresses(CharSequence) */ public static boolean isValidEmailAddress(final CharSequence cs) { if (isEmpty(cs)) { return false; } return EMAIL_ADDRESS_RFC_5322_PATTERN.matcher(cs).matches(); } /** * Checks if the given CharSequence is a valid URL. * * This method uses a regular expression to validate the URL. It checks for the general form of a URL * which includes protocol, domain, port, path, query parameters, and fragment identifier. * * @param cs The CharSequence to be checked. It can be {@code null} or empty. * @return {@code true} if the CharSequence is a valid URL, {@code false} otherwise. */ public static boolean isValidUrl(final CharSequence cs) { if (isEmpty(cs)) { return false; } return URL_PATTERN.matcher(cs).matches(); } /** * Checks if the given CharSequence is a valid HTTP URL. * * This method uses a regular expression to validate the URL. It checks for the general form of a URL * which includes protocol, domain, port, path, query parameters, and fragment identifier. * The URL must start with http:// or https://. * * @param cs The CharSequence to be checked. It can be {@code null} or empty. * @return {@code true} if the CharSequence is a valid HTTP URL, {@code false} otherwise. */ public static boolean isValidHttpUrl(final CharSequence cs) { if (isEmpty(cs)) { return false; } return HTTP_URL_PATTERN.matcher(cs).matches(); } /** * Checks if the specified {@code CharSequence} is {@code null} or empty. * * @param cs * @return */ public static boolean isEmpty(final CharSequence cs) { return (cs == null) || (cs.isEmpty()); } /** * Checks if the given CharSequence is {@code null} or contains only whitespace characters. * * @param cs The CharSequence to be checked. It can be {@code null} or empty. * @return {@code true} if the CharSequence is {@code null} or contains only whitespace characters, {@code false} otherwise. */ public static boolean isBlank(final CharSequence cs) { if (isEmpty(cs)) { return true; } if (cs instanceof String) { return ((String) cs).isBlank(); } for (int i = 0, len = cs.length(); i < len; i++) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } /** * Checks if the given CharSequence is not {@code null} and not empty. * * @param cs The CharSequence to be checked. It can be {@code null}. * @return {@code true} if the CharSequence is not {@code null} and not empty, {@code false} otherwise. */ public static boolean isNotEmpty(final CharSequence cs) { return (cs != null) && (!cs.isEmpty()); } /** * Checks if the given CharSequence is not {@code null} and contains non-whitespace characters. * * @param cs The CharSequence to be checked. It can be {@code null}. * @return {@code true} if the CharSequence is not {@code null} and contains non-whitespace characters, {@code false} otherwise. */ @Beta public static boolean isNotBlank(final CharSequence cs) { return !isBlank(cs); } // /** // * // * @param cs // * @return // */ // public static boolean notBlank(final CharSequence cs) { // return !isBlank(cs); // } // // /** // * // * @param cs // * @return // */ // @Beta // public static boolean notEmpty(final CharSequence cs) { // return (cs != null) && (cs.length() > 0); // } /** * Checks if both of the provided CharSequences are empty or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @return {@code true} if both CharSequences are {@code null} or empty, {@code false} otherwise. */ public static boolean isAllEmpty(final CharSequence a, final CharSequence b) { return isEmpty(a) && isEmpty(b); } /** * Checks if all the provided CharSequences are empty or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @param c The third CharSequence to be checked. It can be {@code null}. * @return {@code true} if all CharSequences are {@code null} or empty, {@code false} otherwise. */ public static boolean isAllEmpty(final CharSequence a, final CharSequence b, final CharSequence c) { return isEmpty(a) && isEmpty(b) && isEmpty(c); } /** *

Checks if all the CharSequences are empty ("") or {@code null}.

* *
     * Strings.isAllEmpty(null)             = true
     * Strings.isAllEmpty(null, "")         = true
     * Strings.isAllEmpty(new String[] {})  = true
     * Strings.isAllEmpty(null, "foo")      = false
     * Strings.isAllEmpty("", "bar")        = false
     * Strings.isAllEmpty("bob", "")        = false
     * Strings.isAllEmpty("  bob  ", null)  = false
     * Strings.isAllEmpty(" ", "bar")       = false
     * Strings.isAllEmpty("foo", "bar")     = false
     * 
* * @param css the CharSequences to check, may be {@code null} or empty * @return {@code true} if all the CharSequences are empty or null * @see Strings#isAllEmpty(CharSequence...) */ public static boolean isAllEmpty(final CharSequence... css) { if (N.isEmpty(css)) { return true; } for (final CharSequence cs : css) { if (isNotEmpty(cs)) { return false; } } return true; } /** * Checks if all the provided CharSequences in the Iterable are empty or {@code null}. * * @param css The Iterable of CharSequences to be checked. It can be {@code null}. * @return {@code true} if all CharSequences in the Iterable are {@code null} or empty, {@code false} otherwise. */ public static boolean isAllEmpty(final Iterable css) { if (N.isEmpty(css)) { return true; } for (final CharSequence cs : css) { if (isNotEmpty(cs)) { return false; } } return true; } /** * Checks if both of the provided CharSequences are blank or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @return {@code true} if both CharSequences are {@code null} or blank, {@code false} otherwise. */ public static boolean isAllBlank(final CharSequence a, final CharSequence b) { return isBlank(a) && isBlank(b); } /** * Checks if all the provided CharSequences are blank or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @param c The third CharSequence to be checked. It can be {@code null}. * @return {@code true} if all CharSequences are {@code null} or blank, {@code false} otherwise. */ public static boolean isAllBlank(final CharSequence a, final CharSequence b, final CharSequence c) { return isBlank(a) && isBlank(b) && isBlank(c); } /** *

Checks if all the CharSequences are empty (""), {@code null} or whitespace only.

* *

Whitespace is defined by {@link Character#isWhitespace(char)}.

* *
     * Strings.isAllBlank(null)             = true
     * Strings.isAllBlank(null, "foo")      = false
     * Strings.isAllBlank(null, null)       = true
     * Strings.isAllBlank("", "bar")        = false
     * Strings.isAllBlank("bob", "")        = false
     * Strings.isAllBlank("  bob  ", null)  = false
     * Strings.isAllBlank(" ", "bar")       = false
     * Strings.isAllBlank("foo", "bar")     = false
     * Strings.isAllBlank(new String[] {})  = true
     * 
* * @param css the CharSequences to check, may be {@code null} or empty * @return {@code true} if all the CharSequences are empty or {@code null} or whitespace only * @see Strings#isAllBlank(CharSequence...) */ public static boolean isAllBlank(final CharSequence... css) { if (N.isEmpty(css)) { return true; } for (final CharSequence cs : css) { if (isNotBlank(cs)) { return false; } } return true; } /** * Checks if all the provided CharSequences in the Iterable are blank or {@code null}. * * @param css The Iterable of CharSequences to be checked. It can be {@code null}. * @return {@code true} if all CharSequences in the Iterable are {@code null} or blank, {@code false} otherwise. */ public static boolean isAllBlank(final Iterable css) { if (N.isEmpty(css)) { return true; } for (final CharSequence cs : css) { if (isNotBlank(cs)) { return false; } } return true; } /** * Checks if any of the provided CharSequences are empty or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @return {@code true} if any of the CharSequences are {@code null} or empty, {@code false} otherwise. */ public static boolean isAnyEmpty(final CharSequence a, final CharSequence b) { return isEmpty(a) || isEmpty(b); } /** * Checks if any of the provided CharSequences are empty or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @param c The third CharSequence to be checked. It can be {@code null}. * @return {@code true} if any of the CharSequences are {@code null} or empty, {@code false} otherwise. */ public static boolean isAnyEmpty(final CharSequence a, final CharSequence b, final CharSequence c) { return isEmpty(a) || isEmpty(b) || isEmpty(c); } /** *

Checks if any of the CharSequences are empty ("") or {@code null}.

* *
     * Strings.isAnyEmpty((String) null)    = true
     * Strings.isAnyEmpty((String[]) null)  = false
     * Strings.isAnyEmpty(null, "foo")      = true
     * Strings.isAnyEmpty("", "bar")        = true
     * Strings.isAnyEmpty("bob", "")        = true
     * Strings.isAnyEmpty("  bob  ", null)  = true
     * Strings.isAnyEmpty(" ", "bar")       = false
     * Strings.isAnyEmpty("foo", "bar")     = false
     * Strings.isAnyEmpty(new String[]{})   = false
     * Strings.isAnyEmpty(new String[]{""}) = true
     * 
* * @param css the CharSequences to check, may be {@code null} or empty * @return {@code true} if any of the CharSequences are empty or null * @see Strings#isAnyEmpty(CharSequence...) */ public static boolean isAnyEmpty(final CharSequence... css) { if (N.isEmpty(css)) { return false; } for (final CharSequence cs : css) { if (isEmpty(cs)) { return true; } } return false; } /** * Checks if any of the provided CharSequences in the Iterable are empty or {@code null}. * * @param css The Iterable of CharSequences to be checked. It can be {@code null}. * @return {@code true} if any CharSequences in the Iterable are {@code null} or empty, {@code false} otherwise. */ public static boolean isAnyEmpty(final Iterable css) { if (N.isEmpty(css)) { return false; } for (final CharSequence cs : css) { if (isEmpty(cs)) { return true; } } return false; } /** * Checks if any of the provided CharSequences are blank or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @return {@code true} if any of the CharSequences are {@code null} or blank, {@code false} otherwise. */ public static boolean isAnyBlank(final CharSequence a, final CharSequence b) { return isBlank(a) || isBlank(b); } /** * Checks if any of the provided CharSequences are blank or {@code null}. * * @param a The first CharSequence to be checked. It can be {@code null}. * @param b The second CharSequence to be checked. It can be {@code null}. * @param c The third CharSequence to be checked. It can be {@code null}. * @return {@code true} if any of the CharSequences are {@code null} or blank, {@code false} otherwise. */ public static boolean isAnyBlank(final CharSequence a, final CharSequence b, final CharSequence c) { return isBlank(a) || isBlank(b) || isBlank(c); } /** *

Checks if any of the CharSequences are empty ("") or {@code null} or whitespace only.

* *

Whitespace is defined by {@link Character#isWhitespace(char)}.

* *
     * Strings.isAnyBlank((String) null)    = true
     * Strings.isAnyBlank((String[]) null)  = false
     * Strings.isAnyBlank(null, "foo")      = true
     * Strings.isAnyBlank(null, null)       = true
     * Strings.isAnyBlank("", "bar")        = true
     * Strings.isAnyBlank("bob", "")        = true
     * Strings.isAnyBlank("  bob  ", null)  = true
     * Strings.isAnyBlank(" ", "bar")       = true
     * Strings.isAnyBlank(new String[] {})  = false
     * Strings.isAnyBlank(new String[]{""}) = true
     * Strings.isAnyBlank("foo", "bar")     = false
     * 
* * @param css the CharSequences to check, may be {@code null} or empty * @return {@code true} if any of the CharSequences are empty or {@code null} or whitespace only * @see Strings#isAnyBlank(CharSequence...) */ public static boolean isAnyBlank(final CharSequence... css) { if (N.isEmpty(css)) { return false; } for (final CharSequence cs : css) { if (isBlank(cs)) { return true; } } return false; } /** * Checks if any of the provided CharSequences in the Iterable are blank or {@code null}. * * @param css The Iterable of CharSequences to be checked. It can be {@code null}. * @return {@code true} if any CharSequences in the Iterable are {@code null} or blank, {@code false} otherwise. */ public static boolean isAnyBlank(final Iterable css) { if (N.isEmpty(css)) { return false; } for (final CharSequence cs : css) { if (isBlank(cs)) { return true; } } return false; } /** * Checks if the input string is wrapped with the specified prefix and suffix string. * * @param str The input string to be checked. * @param prefixSuffix The string that should be the prefix and suffix of the input string. * @return {@code true} if the input string starts and ends with the prefixSuffix string, {@code false} otherwise. * @throws IllegalArgumentException if prefixSuffix is empty. */ public static boolean isWrappedWith(final String str, final String prefixSuffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefixSuffix, cs.prefixSuffix); return str != null && str.length() >= prefixSuffix.length() * 2 && str.startsWith(prefixSuffix) && str.endsWith(prefixSuffix); } /** * Checks if the input string is wrapped with the specified prefix and suffix string. * * @param str The input string to be checked. * @param prefix The string that should be the prefix of the input string. * @param suffix The string that should be the suffix of the input string. * @return {@code true} if the input string starts with the prefix and ends with the suffix, {@code false} otherwise. * @throws IllegalArgumentException if prefix or suffix is empty. */ public static boolean isWrappedWith(final String str, final String prefix, final String suffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefix, cs.prefix); N.checkArgNotEmpty(prefix, cs.suffix); return str != null && str.length() >= prefix.length() + suffix.length() && str.startsWith(prefix) && str.endsWith(suffix); } /** * Returns the first non-empty CharSequence from the given two CharSequences. * * @param The type of the CharSequence. * @param a The first CharSequence to be checked. It can be {@code null} or empty. * @param b The second CharSequence to be checked. It can be {@code null} or empty. * @return The first non-empty CharSequence from the given two CharSequences. If both are empty, returns {@code null}. */ public static T firstNonEmpty(final T a, final T b) { return isEmpty(a) ? (isEmpty(b) ? null : b) : a; } /** * Returns the first non-empty CharSequence from the given three CharSequences. * * @param The type of the CharSequence. * @param a The first CharSequence to be checked. It can be {@code null} or empty. * @param b The second CharSequence to be checked. It can be {@code null} or empty. * @param c The third CharSequence to be checked. It can be {@code null} or empty. * @return The first non-empty CharSequence from the given three CharSequences. If all are empty, returns {@code null}. */ public static T firstNonEmpty(final T a, final T b, final T c) { return isEmpty(a) ? (isEmpty(b) ? (isEmpty(c) ? null : c) : b) : a; } /** *

Returns the first value in the array which is not empty.

* *

If all values are empty or the array is {@code null} or empty then {@code null} is returned.

* *
     * Strings.firstNonEmpty(null, {@code null}, null)   = null
     * Strings.firstNonEmpty(null, {@code null}, "")     = null
     * Strings.firstNonEmpty(null, "", " ")      = " "
     * Strings.firstNonEmpty("abc")              = "abc"
     * Strings.firstNonEmpty(null, "xyz")        = "xyz"
     * Strings.firstNonEmpty("", "xyz")          = "xyz"
     * Strings.firstNonEmpty(null, "xyz", "abc") = "xyz"
     * Strings.firstNonEmpty()                   = null
     * 
* * @param the specific kind of CharSequence * @param css the values to test, may be {@code null} or empty * @return the first value from {@code css} which is not empty, or {@code null} if there is no non-empty value. * @see StrUtil#firstNonEmpty(CharSequence...) */ @MayReturnNull @SafeVarargs public static T firstNonEmpty(final T... css) { if (N.isEmpty(css)) { return null; } for (final T val : css) { if (isNotEmpty(val)) { return val; } } return null; } /** * Returns the first non-empty CharSequence from the given Iterable of CharSequences. * * @param The type of the CharSequence. * @param css The Iterable of CharSequences to be checked. It can be {@code null}. * @return The first non-empty CharSequence from the given Iterable. If all CharSequences are empty or the Iterable is {@code null}, returns {@code null}. */ @MayReturnNull public static T firstNonEmpty(final Iterable css) { if (N.isEmpty(css)) { return null; } for (final T val : css) { if (isNotEmpty(val)) { return val; } } return null; } /** * Returns the first non-blank CharSequence from the given two CharSequences. * * @param The type of the CharSequence. * @param a The first CharSequence to be checked. It can be {@code null} or empty. * @param b The second CharSequence to be checked. It can be {@code null} or empty. * @return The first non-blank CharSequence from the given two CharSequences. If both are blank, returns {@code null}. */ public static T firstNonBlank(final T a, final T b) { return isBlank(a) ? (isBlank(b) ? null : b) : a; } /** * Returns the first non-blank CharSequence from the given three CharSequences. * * @param The type of the CharSequence. * @param a The first CharSequence to be checked. It can be {@code null} or empty. * @param b The second CharSequence to be checked. It can be {@code null} or empty. * @param c The third CharSequence to be checked. It can be {@code null} or empty. * @return The first non-blank CharSequence from the given three CharSequences. If all are blank, returns {@code null}. */ public static T firstNonBlank(final T a, final T b, final T c) { return isBlank(a) ? (isBlank(b) ? (isBlank(c) ? null : c) : b) : a; } /** * Returns the first non-blank CharSequence from the given CharSequences. * * @param The type of the CharSequence. * @param css The CharSequences to be checked. They can be {@code null} or empty. * @return The first non-blank CharSequence from the given CharSequences. If all are blank, returns {@code null}. */ @MayReturnNull @SafeVarargs public static T firstNonBlank(final T... css) { if (N.isEmpty(css)) { return null; } for (final T val : css) { if (isNotBlank(val)) { return val; } } return null; } /** * Returns the first non-blank CharSequence from the given Iterable of CharSequences, or {@code null} if all CharSequences are blank or the Iterable is {@code null}. * * @param The type of the CharSequence. * @param css The Iterable of CharSequences to be checked. It can be {@code null}. * @return The first non-blank CharSequence from the given Iterable. If all CharSequences are blank or the Iterable is {@code null}, returns {@code null}. */ @MayReturnNull public static T firstNonBlank(final Iterable css) { if (N.isEmpty(css)) { return null; } for (final T val : css) { if (isNotBlank(val)) { return val; } } return null; } /** * Returns the input CharSequence if it is not empty, otherwise returns the default CharSequence. * * @param The type of the CharSequence. * @param str The input CharSequence to be checked. It can be {@code null} or empty. * @param defaultStr The default CharSequence to be returned if the input CharSequence is empty. * @return The input CharSequence if it is not empty, otherwise the default CharSequence. * @throws IllegalArgumentException if the specified default charSequence value is {@code null}. * @see #firstNonEmpty(CharSequence, CharSequence) * @see #firstNonBlank(CharSequence, CharSequence) * @see N#firstNonNull(Object, Object) */ public static T defaultIfEmpty(final T str, final T defaultStr) { N.checkArgNotNull(defaultStr, cs.defaultValue); return isEmpty(str) ? defaultStr : str; } /** * Returns the input CharSequence if it is not empty, otherwise returns the result produced by the supplier. * * @param The type of the CharSequence. * @param str The input CharSequence to be checked. It can be {@code null} or empty. * @param supplierForDefaultValue The supplier to be invoked if the input CharSequence is empty. It cannot be {@code null}. * @return The input CharSequence if it is not empty, otherwise the result produced by the supplier. * @see #firstNonEmpty(CharSequence, CharSequence) * @see #firstNonBlank(CharSequence, CharSequence) * @see N#firstNonNull(Object, Object) */ public static T defaultIfEmpty(final T str, final Supplier supplierForDefaultValue) { if (isEmpty(str)) { return N.requireNonNull(supplierForDefaultValue.get()); } return str; } /** * Returns the input CharSequence if it is not blank, otherwise returns the default CharSequence. * * @param The type of the CharSequence. * @param str The input CharSequence to be checked. It can be {@code null} or empty. * @param defaultStr The default CharSequence to be returned if the input CharSequence is blank. * @return The input CharSequence if it is not blank, otherwise the default CharSequence. * @throws IllegalArgumentException if the specified default charSequence value is {@code null}. * @see #firstNonEmpty(CharSequence, CharSequence) * @see #firstNonBlank(CharSequence, CharSequence) * @see N#firstNonNull(Object, Object) */ public static T defaultIfBlank(final T str, final T defaultStr) { N.checkArgNotNull(defaultStr, cs.defaultValue); return isBlank(str) ? defaultStr : str; } /** * Returns the input CharSequence if it is not blank, otherwise returns the result produced by the supplier. * * @param The type of the CharSequence. * @param str The input CharSequence to be checked. It can be {@code null} or empty. * @param supplierForDefaultValue The supplier to be invoked if the input CharSequence is blank. It cannot be {@code null}. * @return The input CharSequence if it is not blank, otherwise the result produced by the supplier. * @see #firstNonEmpty(CharSequence, CharSequence) * @see #firstNonBlank(CharSequence, CharSequence) * @see N#firstNonNull(Object, Object) */ public static T defaultIfBlank(final T str, final Supplier supplierForDefaultValue) { if (isBlank(str)) { return N.requireNonNull(supplierForDefaultValue.get()); } return str; } /** * Converts the specified String to an empty String {@code ""} if it's {@code null}, otherwise returns the original string. * * @param str The input string to be checked. It can be {@code null}. * @return An empty string if the input string is {@code null}, otherwise the original string. */ public static String nullToEmpty(final String str) { return str == null ? EMPTY_STRING : str; } /** * Converts each {@code null} String element in the specified String array to an empty String {@code ""}. * Do nothing if the input array is {@code null} or empty. * * @param strs The input string array to be checked. Each {@code null} element in the array will be converted to an empty string. It can be {@code null} or empty. * @see N#nullToEmpty(String[]) * @see N#nullToEmptyForEach(String[]) */ public static void nullToEmpty(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = strs[i] == null ? EMPTY_STRING : strs[i]; } } /** * Converts the specified String to {@code null} if it's empty, otherwise returns the original string. * * @param str The input string to be checked. It can be {@code null} or empty. * @return {@code null} if the input string is empty, otherwise the original string. */ public static String emptyToNull(final String str) { return str == null || str.isEmpty() ? null : str; } /** * Converts each empty String element in the specified String array to {@code null}. * Do nothing if the input array is {@code null} or empty. * * @param strs The input string array to be checked. Each empty element in the array will be converted to {@code null}. It can be {@code null} or empty. */ public static void emptyToNull(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = strs[i] == null || strs[i].isEmpty() ? null : strs[i]; } } /** * Converts the specified String to an empty String {@code ""} if it's blank, otherwise returns the original string. * * @param str The input string to be checked. It can be {@code null} or empty. * @return An empty string if the input string is blank, otherwise the original string. */ public static String blankToEmpty(final String str) { return isBlank(str) ? EMPTY_STRING : str; } /** * Converts each blank String element in the specified String array to an empty String {@code ""}. * Do nothing if the input array is {@code null} or empty. * * @param strs The input string array to be checked. Each blank element in the array will be converted to an empty string. It can be {@code null} or empty. */ public static void blankToEmpty(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = isBlank(strs[i]) ? EMPTY_STRING : strs[i]; } } /** * Converts the specified String to {@code null} if it's blank, otherwise returns the original string. * * @param str The input string to be checked. It can be {@code null} or empty. * @return {@code null} if the input string is blank, otherwise the original string. */ public static String blankToNull(final String str) { return isBlank(str) ? null : str; } /** * Converts each blank String element in the specified String array to {@code null}. * Do nothing if the input array is {@code null} or empty. * * @param strs The input string array to be checked. Each blank element in the array will be converted to {@code null}. It can be {@code null} or empty. */ public static void blankToNull(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = isBlank(strs[i]) ? null : strs[i]; } } /** *

Abbreviates a String using ellipses. This will turn * "Now is the time for all good men" into "...is the time for..."

* *

Works like {@code abbreviate(String, int)}, but allows you to specify * a "left edge" offset. Note that this left edge is not necessarily going to * be the leftmost character in the result, or the first character following the * ellipses, but it will appear somewhere in the result. * *

In no case will it return a String of length greater than * {@code maxWidth}.

* *
     * Strings.abbreviate(null, 0, 4)                  = null
     * Strings.abbreviate("", 0, 4)                  = ""
     * Strings.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
     * Strings.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
     * Strings.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
     * Strings.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
     * Strings.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
     * Strings.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
     * Strings.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
     * Strings.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
     * Strings.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
     * Strings.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
     * Strings.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
     * 
* * @param str the String to check, may be null * @param offset left edge of source String * @param maxWidth maximum length of result String, must be at least 4 * @return abbreviated String, {@code null} if {@code null} String input * @throws IllegalArgumentException if the width is too small * @deprecated */ @Deprecated static String abbreviate(final String str, final int offset, final int maxWidth) { return abbreviate(str, "...", offset, maxWidth); } // Abbreviating //----------------------------------------------------------------------- /** *

Abbreviates a String using ellipses. This will turn * "Now is the time for all good men" into "Now is the time for..."

* *

Specifically:

*
    *
  • If the number of characters in {@code str} is less than or equal to * {@code maxWidth}, return {@code str}.
  • *
  • Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.
  • *
  • If {@code maxWidth} is less than {@code 4}, throw an * {@code IllegalArgumentException}.
  • *
  • In no case will it return a String of length greater than * {@code maxWidth}.
  • *
* *
     * Strings.abbreviate(null, 4)        = null
     * Strings.abbreviate("", 4)        = ""
     * Strings.abbreviate("abcdefg", 6) = "abc..."
     * Strings.abbreviate("abcdefg", 7) = "abcdefg"
     * Strings.abbreviate("abcdefg", 8) = "abcdefg"
     * Strings.abbreviate("abcdefg", 4) = "a..."
     * Strings.abbreviate("abcdefg", 3) = IllegalArgumentException
     * 
* * @param str the String to check, may be null * @param maxWidth maximum length of result String, must be at least 4 * @return abbreviated String * @throws IllegalArgumentException if the width is too small */ public static String abbreviate(final String str, final int maxWidth) { return abbreviate(str, "...", 0, maxWidth); } /** *

Abbreviates a String using another given String as replacement marker. This will turn * "Now is the time for all good men" into "Now is the time for..." if "..." was defined * as the replacement marker.

* *

Specifically:

*
    *
  • If the number of characters in {@code str} is less than or equal to * {@code maxWidth}, return {@code str}.
  • *
  • Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.
  • *
  • If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an * {@code IllegalArgumentException}.
  • *
  • In no case will it return a String of length greater than * {@code maxWidth}.
  • *
* *
     * Strings.abbreviate(null, "...", 4)        = null
     * Strings.abbreviate("", "...", 4)        = ""
     * Strings.abbreviate("abcdefg", {@code null}, *)  = "abcdefg"
     * Strings.abbreviate("abcdefg", ".", 5)   = "abcd."
     * Strings.abbreviate("abcdefg", ".", 7)   = "abcdefg"
     * Strings.abbreviate("abcdefg", ".", 8)   = "abcdefg"
     * Strings.abbreviate("abcdefg", "..", 4)  = "ab.."
     * Strings.abbreviate("abcdefg", "..", 3)  = "a.."
     * Strings.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
     * Strings.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
     * 
* * @param str the String to check, may be null * @param abbrevMarker the String used as replacement marker * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} * @return abbreviated String * @throws IllegalArgumentException if the width is too small */ public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { return abbreviate(str, abbrevMarker, 0, maxWidth); } /** *

Abbreviates a String using a given replacement marker. This will turn * "Now is the time for all good men" into "...is the time for..." if "..." was defined * as the replacement marker.

* *

Works like {@code abbreviate(String, String, int)}, but allows you to specify * a "left edge" offset. Note that this left edge is not necessarily going to * be the leftmost character in the result, or the first character following the * replacement marker, but it will appear somewhere in the result. * *

In no case will it return a String of length greater than {@code maxWidth}.

* *
     * Strings.abbreviate(null, "...", 0, 4)                  = null
     * Strings.abbreviate("", "...", 0, 4)                  = ""
     * Strings.abbreviate("abcdefghijklmno", {@code null}, *, *)    = "abcdefghijklmno"
     * Strings.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
     * Strings.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
     * Strings.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
     * Strings.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
     * Strings.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
     * Strings.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
     * Strings.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
     * Strings.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
     * Strings.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
     * Strings.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
     * Strings.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
     * 
* * @param str the String to check, may be null * @param abbrevMarker the String used as replacement marker * @param offset left edge of source String * @param maxWidth maximum length of result String, must be at least 4 * @return abbreviated String * @throws IllegalArgumentException if the width is too small * @deprecated */ @Deprecated static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { final int abbrevMarkerLength = N.len(abbrevMarker); final int minAbbrevWidth = abbrevMarkerLength + 1; final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; if (maxWidth < minAbbrevWidth) { throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); } if (isNotEmpty(str) && EMPTY_STRING.equals(abbrevMarker) && maxWidth > 0) { return Strings.substring(str, 0, maxWidth); } else if (isAnyEmpty(str, abbrevMarker)) { return str; } final int strLen = str.length(); if (strLen <= maxWidth) { return str; } if (offset > strLen) { offset = strLen; } if (strLen - offset < maxWidth - abbrevMarkerLength) { offset = strLen - (maxWidth - abbrevMarkerLength); } if (offset <= abbrevMarkerLength + 1) { return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; } if (maxWidth < minAbbrevWidthOffset) { throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); } if (offset + maxWidth - abbrevMarkerLength < strLen) { return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); } return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength)); } /** *

Abbreviates a String to the length passed, replacing the middle characters with the supplied * replacement String.

* *

This abbreviation only occurs if the following criteria is met:

*
    *
  • Neither the String for abbreviation nor the replacement String are {@code null} or empty
  • *
  • The length to truncate to is less than the length of the supplied String
  • *
  • The length to truncate to is greater than 0
  • *
  • The abbreviated String will have enough room for the length supplied replacement String * and the first and last characters of the supplied String for abbreviation
  • *
*

Otherwise, the returned String will be the same as the supplied String for abbreviation. *

* *
     * Strings.abbreviateMiddle(null, {@code null}, 0)      = null
     * Strings.abbreviateMiddle("abc", {@code null}, 0)      = "abc"
     * Strings.abbreviateMiddle("abc", ".", 0)      = "abc"
     * Strings.abbreviateMiddle("abc", ".", 3)      = "abc"
     * Strings.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
     * 
* * @param str the String to abbreviate, may be null * @param middle the String to replace the middle characters with, may be null * @param length the length to abbreviate {@code str} to. * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. */ public static String abbreviateMiddle(final String str, final String middle, final int length) { if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) { return str; } final int targetSting = length - middle.length(); final int startOffset = targetSting / 2 + targetSting % 2; final int endOffset = str.length() - targetSting / 2; return str.substring(0, startOffset) + middle + str.substring(endOffset); } // Centering //----------------------------------------------------------------------- /** *

Centers a String in a larger String of size {@code size} * using the space character (' ').

* *

If the size is less than the String length, the original String is returned. * *

Equivalent to {@code center(str, size, " ")}.

* *
     * Strings.center(null, 4)     = "    "
     * Strings.center("", 4)     = "    "
     * Strings.center("ab", 4)   = " ab "
     * Strings.center("abcd", 2) = "abcd"
     * Strings.center("a", 4)    = " a  "
     * 
* * @param str the String to center, may be null * @param size the int size of new String * @return centered String */ public static String center(final String str, final int size) { return center(str, size, ' '); } /** *

Centers a String in a larger String of size {@code size}. * Uses a supplied character as the value to pad the String with.

* *

If the size is less than the String length, the String is returned. * *

     * Strings.center(null, 4, ' ')     = "    "
     * Strings.center("", 4, ' ')     = "    "
     * Strings.center("ab", 4, ' ')   = " ab "
     * Strings.center("abcd", 2, ' ') = "abcd"
     * Strings.center("a", 4, ' ')    = " a  "
     * Strings.center("a", 4, 'y')    = "yayy"
     * 
* * @param str the String to center, may be null * @param size the int size of new String. * @param padChar the character to pad the new String with * @return centered String * @throws IllegalArgumentException */ public static String center(String str, final int size, final char padChar) throws IllegalArgumentException { N.checkArgNotNegative(size, cs.size); if (str == null) { str = EMPTY_STRING; } if (str.length() >= size) { return str; } final int strLen = str.length(); final int pads = size - strLen; str = padStart(str, strLen + pads / 2, padChar); return padEnd(str, size, padChar); } /** *

Centers a String in a larger String of size {@code minLength}. * Uses a supplied String as the value to pad the String with.

* *

If the size is less than the String length, the String is returned. * *

     * Strings.center(null, 4, " ")     = "    "
     * Strings.center("", 4, " ")     = "    "
     * Strings.center("ab", 4, " ")   = " ab "
     * Strings.center("abcd", 2, " ") = "abcd"
     * Strings.center("a", 4, " ")    = " a  "
     * Strings.center("a", 4, "yz")   = "yzayz"
     * Strings.center("abc", 7, "")   = "  abc  "
     * 
* * @param str the String to center, may be null * @param minLength the minimum size of new String. * @param padStr the String to pad the new String with, must not be {@code null} or empty * @return centered String * @throws IllegalArgumentException */ public static String center(String str, final int minLength, String padStr) throws IllegalArgumentException { N.checkArgNotNegative(minLength, cs.minLength); // N.checkArgNotEmpty(padStr, "padStr"); if (str == null) { str = EMPTY_STRING; } if (str.length() >= minLength) { return str; } if (isEmpty(padStr)) { padStr = " "; } final int strLen = str.length(); final int pads = minLength - strLen; str = padStart(str, strLen + pads / 2, padStr); return padEnd(str, minLength, padStr); } /** * Pads the given string from the start (left) with spaces until the string reaches the specified minimum length. * If the length of the given string is already greater than or equal to the specified minimum length, the original string is returned. * * @param str The string to be padded. It can be {@code null} or empty. * @param minLength The minimum length the string should have after padding. Must be non-negative. * @return A new string that is a copy of the original string padded with leading spaces so that it reaches the specified minimum length. * If the original string is already greater than or equal to the specified minimum length, the original string is returned. */ public static String padStart(final String str, final int minLength) { return padStart(str, minLength, WD._SPACE); } /** * Pads the given string from the start (left) with the specified character until the string reaches the specified minimum length. * If the length of the given string is already greater than or equal to the specified minimum length, the original string is returned. * * @param str The string to be padded. It can be {@code null}, in which case it will be treated as an empty string. * @param minLength The minimum length the string should have after padding. Must be non-negative. * @param padChar The character to be used for padding. * @return A new string that is a copy of the original string padded with the padChar so that it reaches the specified minimum length. * If the original string is already greater than or equal to the specified minimum length, the original string is returned. */ public static String padStart(String str, final int minLength, final char padChar) { if (str == null) { str = EMPTY_STRING; } if (str.length() >= minLength) { return str; } final String padStr = Strings.repeat(padChar, minLength - str.length()); return concat(padStr, str); } /** * Pads the given string from the start (left) with the specified string until the string reaches the specified minimum length. * If the length of the given string is already greater than or equal to the specified minimum length, the original string is returned. * * @param str The string to be padded. It can be {@code null}, in which case it will be treated as an empty string. * @param minLength The minimum length the string should have after padding. Must be non-negative. * @param padStr The string to be used for padding. * @return A new string that is a copy of the original string padded with the padStr so that it reaches the specified minimum length. * If the original string is already greater than or equal to the specified minimum length, the original string is returned. */ public static String padStart(String str, final int minLength, final String padStr) { if (str == null) { str = EMPTY_STRING; } if (str.length() >= minLength) { return str; } @SuppressWarnings("DuplicateExpressions") final int delta = ((minLength - str.length()) % padStr.length() == 0) ? ((minLength - str.length()) / padStr.length()) : ((minLength - str.length()) / padStr.length() + 1); switch (delta) { case 1: return padStr + str; case 2: return padStr + padStr + str; case 3: return padStr + padStr + padStr + str; default: { final StringBuilder sb = Objectory.createStringBuilder(str.length() + (padStr.length() * delta)); try { //noinspection StringRepeatCanBeUsed for (int i = 0; i < delta; i++) { sb.append(padStr); } sb.append(str); return sb.toString(); } finally { Objectory.recycle(sb); } } } } /** * Pads the given string from the end (right) with spaces until the string reaches the specified minimum length. * If the length of the given string is already greater than or equal to the specified minimum length, the original string is returned. * * @param str The string to be padded. It can be {@code null}, in which case it will be treated as an empty string. * @param minLength The minimum length the string should have after padding. Must be non-negative. * @return A new string that is a copy of the original string padded with trailing spaces so that it reaches the specified minimum length. * If the original string is already greater than or equal to the specified minimum length, the original string is returned. */ public static String padEnd(final String str, final int minLength) { return padEnd(str, minLength, WD._SPACE); } /** * Pads the given string from the end (right) with the specified character until the string reaches the specified minimum length. * If the length of the given string is already greater than or equal to the specified minimum length, the original string is returned. * * @param str The string to be padded. It can be {@code null}, in which case it will be treated as an empty string. * @param minLength The minimum length the string should have after padding. Must be non-negative. * @param padChar The character to be used for padding. * @return A new string that is a copy of the original string padded with the padChar so that it reaches the specified minimum length. * If the original string is already greater than or equal to the specified minimum length, the original string is returned. */ public static String padEnd(String str, final int minLength, final char padChar) { if (str == null) { str = EMPTY_STRING; } if (str.length() >= minLength) { return str; } final String padStr = Strings.repeat(padChar, minLength - str.length()); return concat(str, padStr); } /** * Pads the given string from the end (right) with the specified string until the string reaches the specified minimum length. * If the length of the given string is already greater than or equal to the specified minimum length, the original string is returned. * * @param str The string to be padded. It can be {@code null}, in which case it will be treated as an empty string. * @param minLength The minimum length the string should have after padding. Must be non-negative. * @param padStr The string to be used for padding. * @return A new string that is a copy of the original string padded with the padStr so that it reaches the specified minimum length. * If the original string is already greater than or equal to the specified minimum length, the original string is returned. */ public static String padEnd(String str, final int minLength, final String padStr) { if (str == null) { str = EMPTY_STRING; } if (str.length() >= minLength) { return str; } @SuppressWarnings("DuplicateExpressions") final int delta = ((minLength - str.length()) % padStr.length() == 0) ? ((minLength - str.length()) / padStr.length()) : ((minLength - str.length()) / padStr.length() + 1); switch (delta) { case 1: return str + padStr; case 2: return str + padStr + padStr; case 3: return str + padStr + padStr + padStr; default: { final StringBuilder sb = Objectory.createStringBuilder(str.length() + (padStr.length() * delta)); try { sb.append(str); //noinspection StringRepeatCanBeUsed for (int i = 0; i < delta; i++) { sb.append(padStr); } return sb.toString(); } finally { Objectory.recycle(sb); } } } } /** * Repeats the given character a specified number of times and returns the resulting string. * * @param ch The character to be repeated. * @param n The number of times the character should be repeated. Must be non-negative. * @return A string consisting of the given character repeated n times. * @throws IllegalArgumentException if n is negative. */ public static String repeat(final char ch, final int n) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); if (n == 0) { return EMPTY_STRING; } else if (n == 1) { return N.stringOf(ch); } // if (n < 16) { // final char[] array = new char[n]; // Arrays.fill(array, ch); // // return InternalUtil.newString(array, true); // } else { // final char[] array = new char[n]; // array[0] = ch; // // int cnt = 1; // // for (; cnt < n - cnt; cnt <<= 1) { // N.copy(array, 0, array, cnt, cnt); // } // // if (cnt < n) { // N.copy(array, 0, array, cnt, n - cnt); // } // // return InternalUtil.newString(array, true); // } return N.stringOf(ch).repeat(n); } /** * Repeats the given character a specified number of times, separated by a specified delimiter, and returns the resulting string. * * @param ch The character to be repeated. * @param n The number of times the character should be repeated. Must be non-negative. * @param delimiter The character used to separate the repeated characters. * @return A string consisting of the given character repeated n times, separated by the delimiter. * @throws IllegalArgumentException if n is negative. * @see #repeat(char, int, char) * @see #repeat(String, int, String) */ public static String repeat(final char ch, final int n, final char delimiter) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); return repeat(N.stringOf(ch), n, N.stringOf(delimiter)); } /** * Repeats the given string a specified number of times and returns the resulting string. * * @param str The string to be repeated. It can be {@code null} or empty. * @param n The number of times the string should be repeated. Must be non-negative. * @return A string consisting of the given string repeated n times. * @throws IllegalArgumentException if n is negative. * @see #repeat(char, int, char) * @see #repeat(String, int, String) */ public static String repeat(final String str, final int n) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); if (N.isEmpty(str)) { return EMPTY_STRING; } return str.repeat(n); } /** * Repeats the given string a specified number of times, separated by a specified delimiter, and returns the resulting string. * * @param str The string to be repeated. It can be {@code null} or empty. * @param n The number of times the string should be repeated. Must be non-negative. * @param delimiter The string used to separate the repeated strings. * @return A string consisting of the given string repeated n times, separated by the delimiter. * @throws IllegalArgumentException if n is negative. */ public static String repeat(final String str, final int n, final String delimiter) throws IllegalArgumentException { if (N.isEmpty(delimiter)) { return repeat(str, n); } return repeat(str, n, delimiter, EMPTY_STRING, EMPTY_STRING); } /** * Repeats the given string a specified number of times, separated by a specified delimiter, and returns the resulting string. * The resulting string is also prefixed and suffixed with the provided strings. * * @param str The string to be repeated. It can be {@code null} or empty. * @param n The number of times the string should be repeated. Must be non-negative. * @param delimiter The string used to separate the repeated strings. * @param prefix The string to be added at the start of the resulting string. * @param suffix The string to be added at the end of the resulting string. * @return A string consisting of the prefix, the given string repeated n times separated by the delimiter, and the suffix. * @throws IllegalArgumentException if n is negative. */ public static String repeat(String str, final int n, String delimiter, String prefix, String suffix) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); str = str == null ? EMPTY_STRING : str; delimiter = delimiter == null ? EMPTY_STRING : delimiter; prefix = prefix == null ? EMPTY_STRING : prefix; suffix = suffix == null ? EMPTY_STRING : suffix; if (n == 0 || (isEmpty(str) && isEmpty(delimiter))) { return concat(prefix + suffix); } else if (n == 1) { return concat(prefix, str, suffix); } return join(Array.repeat(str, n), delimiter, prefix, suffix); } /** * Returns the byte array returned by {@code String.getBytes()}, or {@code null} if the specified String is {@code null}. * * @param string The input string to be converted. It can be {@code null}. * @return A byte array representation of the input string using the default charset, or {@code null} if the input string is {@code null}. */ @MayReturnNull public static byte[] getBytes(final String string) { return string == null ? null : string.getBytes(); } /** * Returns the byte array returned by {@code String#getBytes(Charset)}, or {@code null} if the specified String is {@code null}. * * @param string * @param charset * @return the encoded bytes */ @MayReturnNull public static byte[] getBytes(final String string, final Charset charset) { return string == null ? null : string.getBytes(charset); } /** * Returns the byte array returned by {@code String#getBytes(Charsets.UTF_8)}, or {@code null} if the specified String is {@code null}. * * @param string * @return */ @MayReturnNull public static byte[] getBytesUtf8(final String string) { return getBytes(string, Charsets.UTF_8); } /** * Returns the char array of the specified CharSequence, or {@code null} if the specified String is {@code null}. * * @param source The input CharSequence to be converted. It can be {@code null}. * @return A char array representation of the input CharSequence. Returns {@code null} if the input CharSequence is {@code null}. */ @MayReturnNull public static char[] toCharArray(final CharSequence source) { if (source == null) { return null; // NOSONAR } else if (source.isEmpty()) { return N.EMPTY_CHAR_ARRAY; } else if (source instanceof String) { return ((String) source).toCharArray(); } final int len = N.len(source); final char[] array = new char[len]; for (int i = 0; i < len; i++) { array[i] = source.charAt(i); } return array; } /** *

Converts a {@code CharSequence} into an array of code points.

* *

Valid pairs of surrogate code units will be converted into a single supplementary * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or * a low surrogate not preceded by a high surrogate) will be returned as-is.

* *
     * Strings.toCodePoints(null)   =  null
     * Strings.toCodePoints("")     =  []  // empty array
     * 
* * @param str the character sequence to convert * @return */ @MayReturnNull public static int[] toCodePoints(final CharSequence str) { if (str == null) { return null; // NOSONAR } else if (str.isEmpty()) { return N.EMPTY_INT_ARRAY; } final String s = str.toString(); // final int[] result = new int[s.codePointCount(0, s.length())]; // int index = 0; // // for (int i = 0; i < result.length; i++) { // result[i] = s.codePointAt(index); // index += Character.charCount(result[i]); // } // // return result; return s.codePoints().toArray(); } // Case conversion // ----------------------------------------------------------------------- /** * To lower case. * * @param ch * @return * @see Character#toLowerCase(char) */ public static char toLowerCase(final char ch) { return Character.toLowerCase(ch); } /** *

* Converts a String to lower case as per {@link String#toLowerCase()}. *

* *

* A {@code null} input String returns {@code null}. *

* *
     * Strings.toLowerCase(null)  = null
     * Strings.toLowerCase("")    = ""
     * Strings.toLowerCase("aBc") = "abc"
     * 
* *

* Note: As described in the documentation for * {@link String#toLowerCase()}, the result of this method is affected by * the current locale. For platform-independent case transformations, the * method {@link #toLowerCase(String, Locale)} should be used with a specific * locale (e.g. {@link Locale#ENGLISH}). *

* * @param str * the String to lower case, may be null * @return the specified String if it's {@code null} or empty. */ public static String toLowerCase(final String str) { if (str == null || str.isEmpty()) { return str; } return str.toLowerCase(); } /** *

* Converts a String to lower case as per {@link String#toLowerCase(Locale)} * . *

* *

* A {@code null} input String returns {@code null}. *

* *
     * Strings.toLowerCase(null, Locale.ENGLISH)  = null
     * Strings.toLowerCase("", Locale.ENGLISH)    = ""
     * Strings.toLowerCase("aBc", Locale.ENGLISH) = "abc"
     * 
* * @param str * the String to lower case, may be null * @param locale * the locale that defines the case transformation rules, must * not be null * @return the specified String if it's {@code null} or empty. */ public static String toLowerCase(final String str, final Locale locale) { if (str == null || str.isEmpty()) { return str; } return str.toLowerCase(locale); } /** * Converts the given string to lower case with underscores. * If the input string is {@code null} or empty, it returns the input string. * * @param str the input string to be converted * @return the converted string in lower case with underscores */ public static String toLowerCaseWithUnderscore(final String str) { if (str == null || str.isEmpty()) { return str; } final StringBuilder sb = Objectory.createStringBuilder(str.length() + 16); char ch = 0; try { for (int i = 0, len = str.length(); i < len; i++) { ch = str.charAt(i); if (Character.isUpperCase(ch)) { if (i > 0 && (Character.isLowerCase(str.charAt(i - 1)) || (i < len - 1 && Character.isLowerCase(str.charAt(i + 1))))) { if (!sb.isEmpty() && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) {//NOSONAR sb.append(WD._UNDERSCORE); } } sb.append(Character.toLowerCase(ch)); } else { // if (i > 0 && ((isAsciiNumeric(ch) && !isAsciiNumeric(str.charAt(i - 1))) || (isAsciiNumeric(str.charAt(i - 1)) && !isAsciiNumeric(ch)))) { // if (sb.length() > 0 && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) { // sb.append(WD._UNDERSCORE); // } // } sb.append(ch); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * To upper case. * * @param ch * @return * @see Character#toUpperCase(char) */ public static char toUpperCase(final char ch) { return Character.toUpperCase(ch); } /** *

* Converts a String to upper case as per {@link String#toUpperCase()}. *

* *

* A {@code null} input String returns {@code null}. *

* *
     * Strings.toUpperCase(null)  = null
     * Strings.toUpperCase("")    = ""
     * Strings.toUpperCase("aBc") = "ABC"
     * 
* *

* Note: As described in the documentation for * {@link String#toUpperCase()}, the result of this method is affected by * the current locale. For platform-independent case transformations, the * method {@link #toLowerCase(String, Locale)} should be used with a specific * locale (e.g. {@link Locale#ENGLISH}). *

* * @param str the String to upper case, may be null * @return the specified String if it's {@code null} or empty. */ public static String toUpperCase(final String str) { if (str == null || str.isEmpty()) { return str; } return str.toUpperCase(); } /** *

* Converts a String to upper case as per {@link String#toUpperCase(Locale)} * . *

* *

* A {@code null} input String returns {@code null}. *

* *
     * Strings.toUpperCase(null, Locale.ENGLISH)  = null
     * Strings.toUpperCase("", Locale.ENGLISH)    = ""
     * Strings.toUpperCase("aBc", Locale.ENGLISH) = "ABC"
     * 
* * @param str * the String to upper case, may be null * @param locale * the locale that defines the case transformation rules, must * not be null * @return the specified String if it's {@code null} or empty. */ public static String toUpperCase(final String str, final Locale locale) { if (str == null || str.isEmpty()) { return str; } return str.toUpperCase(locale); } /** * Converts the given string to upper case with underscores. * If the input string is {@code null} or empty, it returns the input string. * * @param str the input string to be converted * @return the converted string in upper case with underscores */ public static String toUpperCaseWithUnderscore(final String str) { if (str == null || str.isEmpty()) { return str; } final StringBuilder sb = Objectory.createStringBuilder(str.length() + 16); char ch = 0; try { for (int i = 0, len = str.length(); i < len; i++) { ch = str.charAt(i); if (Character.isUpperCase(ch)) { if (i > 0 && (Character.isLowerCase(str.charAt(i - 1)) || (i < len - 1 && Character.isLowerCase(str.charAt(i + 1))))) { if (!sb.isEmpty() && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) {//NOSONAR sb.append(WD._UNDERSCORE); } } sb.append(ch); } else { // if (i > 0 && ((isAsciiNumeric(ch) && !isAsciiNumeric(str.charAt(i - 1))) || (isAsciiNumeric(str.charAt(i - 1)) && !isAsciiNumeric(ch)))) { // if (sb.length() > 0 && sb.charAt(sb.length() - 1) != WD._UNDERSCORE) { // sb.append(WD._UNDERSCORE); // } // } sb.append(Character.toUpperCase(ch)); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Converts the specified string to camel case. * * @param str The input string to be converted. It can be {@code null} or empty. * @return A camel case representation of the input string. Returns the original string if it's {@code null} or empty. */ public static String toCamelCase(final String str) { if (str == null || str.isEmpty()) { return str; } if (str.indexOf(WD._UNDERSCORE) >= 0) { final String[] substrs = Strings.split(str, WD._UNDERSCORE); final StringBuilder sb = Objectory.createStringBuilder(str.length()); try { for (final String substr : substrs) { if (isNotEmpty(substr)) { sb.append(Strings.toLowerCase(substr)); if (sb.length() > substr.length()) { sb.setCharAt(sb.length() - substr.length(), Character.toTitleCase(substr.charAt(0))); } } } return sb.toString(); } finally { Objectory.recycle(sb); } } for (int i = 0, len = str.length(); i < len; i++) { if (Character.isLowerCase(str.charAt(i))) { if (i == 1) { return Strings.uncapitalize(str); } else if (i > 1) { return str.substring(0, i - 1).toLowerCase() + str.substring(i - 1); } break; } else if ((i + 1) == str.length()) { return str.toLowerCase(); } } return str; } /** * Swaps the case of a character changing upper and title case to lower case, and lower case to upper case. * * @param ch The input character to be case-swapped. * @return The case-swapped representation of the input character. */ public static char swapCase(final char ch) { return Character.isUpperCase(ch) || Character.isTitleCase(ch) ? Character.toLowerCase(ch) : (Character.isLowerCase(ch) ? Character.toUpperCase(ch) : ch); } /** *

* Swaps the case of a String changing upper and title case to lower case, and lower case to upper case. *

* *
    *
  • Upper case character converts to Lower case
  • *
  • Title case character converts to Lower case
  • *
  • Lower case character converts to Upper case
  • *
* *

* For a word based algorithm, see * {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. A * {@code null} input String returns {@code null}. *

* *
     * Strings.swapCase(null)                 = null
     * Strings.swapCase("")                   = ""
     * Strings.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
     * 
* *

* NOTE: This method changed in Lang version 2.0. It no longer performs a * word based algorithm. If you only use ASCII, you will notice no change. * That functionality is available in * org.apache.commons.lang3.text.WordUtils. *

* * @param str the String to swap case, may be null * @return the specified String if it's {@code null} or empty. */ public static String swapCase(final String str) { if (isEmpty(str)) { return str; } final int strLen = str.length(); final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array int outOffset = 0; int oldCodepoint, newCodePoint; for (int i = 0; i < strLen; i += Character.charCount(newCodePoint)) { oldCodepoint = str.codePointAt(i); if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) { newCodePoint = Character.toLowerCase(oldCodepoint); } else if (Character.isLowerCase(oldCodepoint)) { newCodePoint = Character.toUpperCase(oldCodepoint); } else { newCodePoint = oldCodepoint; } newCodePoints[outOffset++] = newCodePoint; } return new String(newCodePoints, 0, outOffset); } // Copied from Apache commons Lang under Apache License v2. /** * Converts the first character of the given string to lower case. * If the string is {@code null} or empty, the original string is returned. * * @param str The string to be uncapitalized. It can be {@code null} or empty. * @return A string with its first character converted to lower case. * If the original string is already starting with a lower case character, the original string is returned. */ public static String uncapitalize(final String str) { if (str == null || str.isEmpty()) { return str; } final int firstCodePoint = str.codePointAt(0); final int newCodePoint = Character.toLowerCase(firstCodePoint); if (firstCodePoint == newCodePoint) { // already uncapitalize return str; } final int strLen = str.length(); final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array int outOffset = 0; newCodePoints[outOffset++] = newCodePoint; // copy the first code point for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen;) { final int codePoint = str.codePointAt(inOffset); newCodePoints[outOffset++] = codePoint; // copy the remaining ones inOffset += Character.charCount(codePoint); } return new String(newCodePoints, 0, outOffset); } // Copied from Apache commons Lang under Apache License v2. /** * Converts the first character of the given string to upper case. * If the string is {@code null} or empty, the original string is returned. * * @param str The string to be capitalized. It can be {@code null} or empty. * @return A string with its first character converted to upper case. * If the original string is already starting with an upper case character, the original string is returned. */ public static String capitalize(final String str) { if (str == null || str.isEmpty()) { return str; } final int firstCodepoint = str.codePointAt(0); final int newCodePoint = Character.toTitleCase(firstCodepoint); if (firstCodepoint == newCodePoint) { // already capitalized return str; } final int strLen = str.length(); final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array int outOffset = 0; newCodePoints[outOffset++] = newCodePoint; // copy the first code point for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen;) { final int codePoint = str.codePointAt(inOffset); newCodePoints[outOffset++] = codePoint; // copy the remaining ones inOffset += Character.charCount(codePoint); } return new String(newCodePoints, 0, outOffset); } /** * Capitalize all the words from the specified split by {@code ' '}. * * @param str * @return the specified String if it's {@code null} or empty. */ public static String capitalizeFully(final String str) { return capitalizeFully(str, " "); } /** * Capitalize all the words from the specified split by {@code delimiter}. * * @param str * @param delimiter * @return the specified String if it's {@code null} or empty. * @throws IllegalArgumentException * @see #convertWords(String, String, Collection, Function) */ public static String capitalizeFully(final String str, final String delimiter) throws IllegalArgumentException { N.checkArgNotEmpty(delimiter, cs.delimiter); // NOSONAR if (str == null || str.isEmpty()) { return str; } final String[] words = splitPreserveAllTokens(str, delimiter); for (int i = 0; i < words.length; i++) { words[i] = capitalize(words[i]); } return join(words, delimiter); } /** * Capitalize all the words from the specified split by {@code delimiter}. * * @param str * @param delimiter * @param excludedWords * @return the specified String if it's {@code null} or empty. * @throws IllegalArgumentException * @see #convertWords(String, String, Collection, Function) */ public static String capitalizeFully(final String str, final String delimiter, final String... excludedWords) throws IllegalArgumentException { N.checkArgNotEmpty(delimiter, cs.delimiter); // NOSONAR if (str == null || str.isEmpty()) { return str; } if (N.isEmpty(excludedWords)) { return capitalizeFully(str, delimiter); } return capitalizeFully(str, delimiter, N.toSet(excludedWords)); } /** * Capitalizes all the words in the given string, split by the provided delimiter, excluding the words in the excludedWords collection. * * @param str The string to be processed. If it's {@code null} or empty, the method will return the input string. * @param delimiter The delimiter used to split the string into words. It must not be empty. * @param excludedWords A collection of words to be excluded from capitalization. If it's {@code null} or empty, all words will be capitalized. * @return The processed string with all non-excluded words capitalized. * @throws IllegalArgumentException if the provided delimiter is empty. * @see #convertWords(String, String, Collection, Function) */ public static String capitalizeFully(final String str, final String delimiter, final Collection excludedWords) throws IllegalArgumentException { N.checkArgNotEmpty(delimiter, cs.delimiter); // NOSONAR if (str == null || str.isEmpty()) { return str; } if (N.isEmpty(excludedWords)) { return capitalizeFully(str, delimiter); } final String[] words = splitPreserveAllTokens(str, delimiter); final Collection excludedWordSet = excludedWords instanceof Set || (excludedWords.size() <= 3 && words.length <= 3) ? excludedWords : N.newHashSet(excludedWords); for (int i = 0, len = words.length; i < len; i++) { words[i] = excludedWordSet.contains(words[i]) ? words[i] : capitalize(words[i]); } return join(words, delimiter); } /** * Converts all the words in the given string using the provided converter function. * The words are identified by splitting the string on space characters. * * @param str The string to be processed. If it's {@code null} or empty, the method will return the input string. * @param converter The function used to convert each word. This function should accept a string and return a string. * @return The processed string with all words converted using the provided converter function. */ public static String convertWords(final String str, final Function converter) { return convertWords(str, " ", converter); } /** * Converts all the words from the specified string, split by the provided delimiter, using the provided converter function. * * @param str The string to be processed. If it's {@code null} or empty, the method will return the input string. * @param delimiter The delimiter used to split the string into words. It must not be empty. * @param converter The function used to convert each word. * @return The processed string with all words converted using the provided converter function. * @throws IllegalArgumentException if the provided delimiter is empty. */ public static String convertWords(final String str, final String delimiter, final Function converter) throws IllegalArgumentException { N.checkArgNotEmpty(delimiter, cs.delimiter); // NOSONAR if (str == null || str.isEmpty()) { return str; } final String[] words = splitPreserveAllTokens(str, delimiter); for (int i = 0, len = words.length; i < len; i++) { words[i] = converter.apply(words[i]); } return join(words, delimiter); } /** * Converts all the words from the specified string, split by the provided delimiter, using the provided converter function. * Words that are present in the excludedWords collection are not converted. * * @param str The string to be processed. If it's {@code null} or empty, the method will return the input string. * @param delimiter The delimiter used to split the string into words. It must not be empty. * @param excludedWords A collection of words to be excluded from conversion. If it's {@code null} or empty, all words will be converted. * @param converter The function used to convert each word. If a word is in the excludedWords collection, it will not be converted. * @return The processed string with all non-excluded words converted using the provided converter function. * @throws IllegalArgumentException if the provided delimiter is empty. */ public static String convertWords(final String str, final String delimiter, final Collection excludedWords, final Function converter) throws IllegalArgumentException { N.checkArgNotEmpty(delimiter, cs.delimiter); // NOSONAR if (str == null || str.isEmpty()) { return str; } if (N.isEmpty(excludedWords)) { return convertWords(str, delimiter, converter); } final String[] words = splitPreserveAllTokens(str, delimiter); final Collection excludedWordSet = excludedWords instanceof Set || (excludedWords.size() <= 3 && words.length <= 3) ? excludedWords : N.newHashSet(excludedWords); for (int i = 0, len = words.length; i < len; i++) { words[i] = excludedWordSet.contains(words[i]) ? words[i] : converter.apply(words[i]); } return join(words, delimiter); } /** * Replace ''' or '"' with \' or \" if the previous char of the * quotation is not '\'. original String is returned if the specified String * is {@code null} or empty. * * @param str * @return the specified String if it's {@code null} or empty. */ public static String quoteEscaped(final String str) { if (str == null || str.isEmpty()) { return str; } final StringBuilder sb = Objectory.createStringBuilder(str.length() + 16); try { char ch = 0; for (int i = 0, len = str.length(); i < len; i++) { ch = str.charAt(i); if ((ch == _BACKSLASH) && (i < (len - 1))) { sb.append(ch); sb.append(str.charAt(++i)); } else { if ((ch == _QUOTATION_S) || (ch == _QUOTATION_D)) { sb.append(_BACKSLASH); } sb.append(ch); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Escapes the specified quotation character in the given string if it is not already escaped. * * @param str the input string to be processed, may be {@code null} or empty * @param quoteChar the quotation character to be escaped, should be either {@code "} or {@code '} * @return the processed string with the specified quotation character escaped, or the original string if it is {@code null} or empty */ public static String quoteEscaped(final String str, final char quoteChar) { if (str == null || str.isEmpty()) { return str; } final StringBuilder sb = Objectory.createStringBuilder(str.length() + 16); try { char ch = 0; for (int i = 0, len = str.length(); i < len; i++) { ch = str.charAt(i); if ((ch == _BACKSLASH) && (i < (len - 1))) { sb.append(ch); sb.append(str.charAt(++i)); } else { if (ch == quoteChar) { sb.append(_BACKSLASH); } sb.append(ch); } } return sb.toString(); } finally { Objectory.recycle(sb); } } // -------------------------------------------------------------------------- /** *

* Converts the char to the unicode format '\u0020'. *

* *

* This format is the Java source code format. *

* *
     *   Strings.unicodeEscaped(' ') = "\u0020"
     *   Strings.unicodeEscaped('A') = "\u0041"
     * 
* * @param ch * the character to convert * @return */ public static String unicodeEscaped(final char ch) { if (ch < 0x10) { return "\\u000" + Integer.toHexString(ch); } else if (ch < 0x100) { return "\\u00" + Integer.toHexString(ch); } else if (ch < 0x1000) { return "\\u0" + Integer.toHexString(ch); } return "\\u" + Integer.toHexString(ch); } /** *

* Similar to * http://www.w3.org/TR/xpath/#function-normalize -space *

*

* The function returns the argument string with whitespace normalized by * using {@link #trim(String)} to remove leading and trailing * whitespace and then replacing sequences of whitespace characters by a * single space. *

* In XML Whitespace characters are the same as those allowed by the S production, which is S * ::= (#x20 | #x9 | #xD | #xA)+ *

* Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] * *

* For reference: *

*
    *
  • \x0B = vertical tab
  • *
  • \f = #xC = form feed
  • *
  • #x20 = space
  • *
  • #x9 = \t
  • *
  • #xA = \n
  • *
  • #xD = \r
  • *
* *

* The difference is that Java's whitespace includes vertical tab and form * feed, which this functional will also normalize. Additionally * {@link #trim(String)} removes control characters (char <= * 32) from both ends of this String. *

* * @param str the source String to normalize whitespaces from, may be null * @return * {@code null} String input * @see Pattern * @see #trim(String) * @see http://www.w3.org/TR/xpath/#function-normalize-space */ public static String normalizeSpace(final String str) { if (str == null || str.isEmpty()) { return str; } return WHITESPACE_PATTERN.matcher(str.trim()).replaceAll(WD.SPACE); } /** *

* Replaces all occurrences of a String within another String. *

* *

* A {@code null} reference passed to this method is a no-op. *

* *
     * Strings.replaceAll(null, *, *)        = null
     * Strings.replaceAll("", *, *)          = ""
     * Strings.replaceAll("any", {@code null}, *)    = "any"
     * Strings.replaceAll("any", *, null)    = "any"
     * Strings.replaceAll("any", "", *)      = "any"
     * Strings.replaceAll("aba", "a", null)  = "b"
     * Strings.replaceAll("aba", "a", "")    = "b"
     * Strings.replaceAll("aba", "a", "z")   = "zbz"
     * 
* * @param str text to search and replace in, may be null * @param target the String to search for, may be null * @param replacement the String to replace it with, may be null * @return */ public static String replaceAll(final String str, final String target, final String replacement) { return replaceAll(str, 0, target, replacement); } /** * Replaces all occurrences of a target string in the input string with a replacement string, starting from a specified index. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with all occurrences of the target string replaced with the replacement string, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceAll(final String str, final int fromIndex, final String target, final String replacement) { return replace(str, fromIndex, target, replacement, -1); } /** * Replaces the first occurrence of a target string in the input string with a replacement string. * *
     * Strings.replaceFirst(null, *, *)        = null
     * Strings.replaceFirst("", *, *)          = ""
     * Strings.replaceFirst("any", {@code null}, *)    = "any"
     * Strings.replaceFirst("any", *, null)    = "any"
     * Strings.replaceFirst("any", "", *)      = "any"
     * Strings.replaceFirst("aba", "a", null)  = "ba"
     * Strings.replaceFirst("aba", "a", "")    = "ba"
     * Strings.replaceFirst("aba", "a", "z")   = "zba"
     * 
* * @param str * @param target * @param replacement the String to replace with, may be null * @return the text with any replacements processed, * {@code null} if {@code null} String input */ public static String replaceFirst(final String str, final String target, final String replacement) { return replaceFirst(str, 0, target, replacement); } /** * Replaces the first occurrence of a target string in the input string with a replacement string, starting from a specified index. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the first occurrence of the target string replaced with the replacement string, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceFirst(final String str, final int fromIndex, final String target, final String replacement) { return replace(str, fromIndex, target, replacement, 1); } /** * Replaces the first occurrence of a target string in the input string with a replacement string. * *
     * Strings.replaceOnce(null, *, *)        = null
     * Strings.replaceOnce("", *, *)          = ""
     * Strings.replaceOnce("any", {@code null}, *)    = "any"
     * Strings.replaceOnce("any", *, null)    = "any"
     * Strings.replaceOnce("any", "", *)      = "any"
     * Strings.replaceOnce("aba", "a", null)  = "ba"
     * Strings.replaceOnce("aba", "a", "")    = "ba"
     * Strings.replaceOnce("aba", "a", "z")   = "zba"
     * 
* * @param str The input string where the replacement should occur. It can be {@code null}. * @param target The string to be replaced. It can be {@code null}. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the first occurrence of the target string replaced with the replacement string. * If the input string, target string, or replacement string is {@code null}, the method returns the original string. * @deprecated Use {@link #replaceFirst(String, String, String)} instead */ @Deprecated public static String replaceOnce(final String str, final String target, final String replacement) { return replaceFirst(str, target, replacement); } /** * Replaces the first occurrence of a target string in the input string with a replacement string, starting from a specified index. * * @param str * @param fromIndex * @param target * @param replacement * @return * @deprecated Use {@link #replaceFirst(String, int, String, String)} instead */ @Deprecated public static String replaceOnce(final String str, final int fromIndex, final String target, final String replacement) { return replaceFirst(str, fromIndex, target, replacement); } /** * Replaces the last occurrence of a target string in the input string with a replacement string. * *
     * Strings.replaceLast(null, *, *)        = null
     * Strings.replaceLast("", *, *)          = ""
     * Strings.replaceLast("any", {@code null}, *)    = "any"
     * Strings.replaceLast("any", *, null)    = "any"
     * Strings.replaceLast("any", "", *)      = "any"
     * Strings.replaceLast("aba", "a", null)  = "ab"
     * Strings.replaceLast("aba", "a", "")    = "ab"
     * Strings.replaceLast("aba", "a", "z")   = "abz"
     * 
* * @param str * @param target * @param replacement the String to replace with, may be null * @return A new string with the last occurrence of the target string replaced with the replacement string. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceLast(final String str, final String target, final String replacement) { return replaceLast(str, N.len(str), target, replacement); } /** * Replaces the last occurrence of a target string in the input string with a replacement string, starting from a specified index backward. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param startIndexFromBack The index to start the search from, searching backward. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the last occurrence of the target string replaced with the replacement string, starting from the specified index backward. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceLast(final String str, final int startIndexFromBack, final String target, final String replacement) { if (isEmpty(str) || isEmpty(target) || startIndexFromBack < 0) { return str; } final int lastIndex = lastIndexOf(str, target, startIndexFromBack); if (lastIndex < 0) { return str; } return Strings.replaceRange(str, lastIndex, lastIndex + N.len(target), replacement); } /** * Replaces occurrences of a target string in the input string with a replacement string, starting from a specified index and up to a maximum number of replacements. * *

* A {@code null} reference passed to this method is a no-op. *

* *
     * replace(null, *, *, *)         = null
     * replace("", *, *, *)           = ""
     * replace("any", {@code null}, *, *)     = "any"
     * replace("any", "", *, *)       = "any"
     * replace("any", *, *, 0)        = "any"
     * replace("abaa", 0, "a", {@code null}, -1) = "b"
     * replace("abaa", 0, "a", "", -1)   = "b"
     * replace("abaa", 0, "a", "z", 0)   = "abaa"
     * replace("abaa", 0, "a", "z", 1)   = "zbaa"
     * replace("abaa", 0, "a", "z", 2)   = "zbza"
     * replace("abaa", 0, "a", "z", -1)  = "zbzz"
     * 
* * @param str The input string where the replacement should occur. It can be {@code null}. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null}. * @param replacement The string to replace the target string. It cannot be {@code null}. * @param max The maximum number of replacements. If it's -1, all occurrences will be replaced. * @return A new string with occurrences of the target string replaced with the replacement string, starting from the specified index and up to the maximum number of replacements. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replace(final String str, final int fromIndex, final String target, final String replacement, final int max) { return replace(str, fromIndex, target, replacement, max, false); } /** * Replaces all occurrences of a target string in the input string with a replacement string, ignoring case considerations. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with all occurrences of the target string replaced with the replacement string, ignoring case considerations. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceAllIgnoreCase(final String str, final String target, final String replacement) { return replaceAllIgnoreCase(str, 0, target, replacement); } /** * Replaces all occurrences of a target string in the input string with a replacement string, ignoring case considerations, starting from a specified index. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with all occurrences of the target string replaced with the replacement string, ignoring case considerations, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceAllIgnoreCase(final String str, final int fromIndex, final String target, final String replacement) { return replaceIgnoreCase(str, fromIndex, target, replacement, -1); } /** * Replaces the first occurrence of a target string in the input string with a replacement string, ignoring case considerations. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the first occurrence of the target string replaced with the replacement string, ignoring case considerations. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceFirstIgnoreCase(final String str, final String target, final String replacement) { return replaceFirstIgnoreCase(str, 0, target, replacement); } /** * Replaces the first occurrence of a target string in the input string with a replacement string, ignoring case considerations, starting from a specified index. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the first occurrence of the target string replaced with the replacement string, ignoring case considerations, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceFirstIgnoreCase(final String str, final int fromIndex, final String target, final String replacement) { return replaceIgnoreCase(str, fromIndex, target, replacement, 1); } /** * Replaces the first occurrence of a target string in the input string with a replacement string, ignoring case considerations. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the first occurrence of the target string replaced with the replacement string, ignoring case considerations. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. * @deprecated Use {@link #replaceFirstIgnoreCase(String, String, String)} instead */ @Deprecated public static String replaceOnceIgnoreCase(final String str, final String target, final String replacement) { return replaceFirstIgnoreCase(str, target, replacement); } /** * Replaces the first occurrence of a target string in the input string with a replacement string, ignoring case considerations, starting from a specified index. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @return A new string with the first occurrence of the target string replaced with the replacement string, ignoring case considerations, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. * @deprecated Use {@link #replaceFirstIgnoreCase(String, int, String, String)} instead */ @Deprecated public static String replaceOnceIgnoreCase(final String str, final int fromIndex, final String target, final String replacement) { return replaceFirstIgnoreCase(str, fromIndex, target, replacement); } /** * Replaces occurrences of a target string in the input string with a replacement string, ignoring case considerations, starting from a specified index and up to a maximum number of replacements. * * @param str The input string where the replacement should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the search for the target string. It should be a non-negative integer. * @param target The string to be replaced. It can be {@code null} or empty. * @param replacement The string to replace the target string. It can be {@code null}. * @param max The maximum number of replacements. If it's -1, all occurrences will be replaced. * @return A new string with occurrences of the target string replaced with the replacement string, ignoring case considerations, starting from the specified index and up to the maximum number of replacements. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the target string is not found, the input string is returned unchanged. */ public static String replaceIgnoreCase(final String str, final int fromIndex, final String target, final String replacement, final int max) { return replace(str, fromIndex, target, replacement, max, true); } private static String replace(final String str, final int fromIndex, final String target, String replacement, int max, final boolean ignoreCase) { // TODO // if (replacement == null) { // throw new IllegalArgumentException("Replacement can't be null"); // } if (isEmpty(str) || isEmpty(target) || max == 0) { return str; } if (replacement == null) { replacement = ""; } final String searchText = ignoreCase ? str.toLowerCase() : str; final String searchTarget = ignoreCase ? target.toLowerCase() : target; int end = searchText.indexOf(searchTarget, fromIndex); if (end == N.INDEX_NOT_FOUND) { return str; } final StringBuilder sb = Objectory.createStringBuilder(str.length() + (N.len(replacement) - N.len(target)) * (N.min(16, max))); final int substrLength = target.length(); sb.append(str, 0, fromIndex); int start = fromIndex; try { while (end != N.INDEX_NOT_FOUND) { sb.append(str, start, end).append(replacement); start = end + substrLength; if (--max == 0) { break; } end = searchText.indexOf(searchTarget, start); } sb.append(str, start, str.length()); return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Replaces each substring of the source String that matches the given * regular expression with the given replacement using the * {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in * Perl. This call is also equivalent to: *
    *
  • {@code source.replaceAll("(?s)" + regex, replacement)}
  • *
  • * {@code Pattern.compile(regex, Pattern.DOTALL).filter(source).replaceAll(replacement)} *
  • *
* * @param source * the source string * @param regex * the regular expression to which this string is to be matched * @param replacement * the string to be substituted for each match * @return The resulting {@code String} * @see String#replaceAll(String, String) * @see Pattern#DOTALL */ public static String replacePattern(final String source, final String regex, final String replacement) { return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement); } /** * Replace the substring specified by the start and end indices with the specified {@code replacement} * * @param str The input string where the replacement should occur. It cannot be {@code null}. * @param fromIndex The start index of the substring to be replaced. It should be a non-negative integer and less than the length of the input string. * @param toIndex The end index of the substring to be replaced. It should be a non-negative integer, greater than the start index and less than or equal to the length of the input string. * @param replacement The string to replace the substring. It cannot be {@code null}. * @return A new string with the specified substring replaced with the replacement string. * @throws IndexOutOfBoundsException If the start or end index is out of the string bounds. * @deprecated Use {@link #replaceRange(String, int, int, String)} instead of this method. * @see #replaceRange(String, int, int, String) */ @Deprecated public static String replace(final String str, final int fromIndex, final int toIndex, final String replacement) throws IndexOutOfBoundsException { return replaceRange(str, fromIndex, toIndex, replacement); } /** * Replaces the substring between two specified delimiters in the given string with a replacement string. * The delimiters themselves are not included in the replaced substring. * * @param str The string to be processed. * @param delimiterOfExclusiveBeginIndex The delimiter after which the replacement should start. * @param delimiterOfExclusiveEndIndex The delimiter before which the replacement should end. * @param replacement The string to replace the substring between the delimiters. If it's {@code null}, the substring between the delimiters will be removed. * @return The processed string with the substring between the delimiters replaced with the replacement string. * If the input string is {@code null} or either of the delimiters is {@code null}, the original string is returned. * @see #substringBetween(String, String, String) */ public static String replaceBetween(final String str, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex, final String replacement) { if (str == null || delimiterOfExclusiveBeginIndex == null || delimiterOfExclusiveEndIndex == null) { return str; } int startIndex = str.indexOf(delimiterOfExclusiveBeginIndex); if (startIndex < 0) { return str; } startIndex += delimiterOfExclusiveBeginIndex.length(); final int endIndex = str.indexOf(delimiterOfExclusiveEndIndex, startIndex); if (endIndex < 0) { return str; } return replace(str, startIndex, endIndex, replacement); } /** * Replaces the substring after a specified delimiter in the given string with a replacement string. * The delimiter itself is not included in the replaced substring. * * @param str The string to be processed. * @param delimiterOfExclusiveBeginIndex The delimiter after which the replacement should start. * @param replacement The string to replace the substring after the delimiter. If it's {@code null}, the substring after the delimiter will be removed. * @return The processed string with the substring after the delimiter replaced with the replacement string. * If the input string is {@code null} or the delimiter is {@code null}, the original string is returned. */ public static String replaceAfter(final String str, final String delimiterOfExclusiveBeginIndex, final String replacement) { if (str == null || delimiterOfExclusiveBeginIndex == null) { return str; } int startIndex = str.indexOf(delimiterOfExclusiveBeginIndex); if (startIndex < 0) { return str; } startIndex += delimiterOfExclusiveBeginIndex.length(); return replace(str, startIndex, str.length(), replacement); } /** * Replaces the substring before a specified delimiter in the given string with a replacement string. * The delimiter itself is not included in the replaced substring. * * @param str The string to be processed. * @param delimiterOfExclusiveEndIndex The delimiter before which the replacement should end. * @param replacement The string to replace the substring before the delimiter. If it's {@code null}, the substring before the delimiter will be removed. * @return The processed string with the substring before the delimiter replaced with the replacement string. * If the input string is {@code null} or the delimiter is {@code null}, the original string is returned. */ public static String replaceBefore(final String str, final String delimiterOfExclusiveEndIndex, final String replacement) { if (str == null || delimiterOfExclusiveEndIndex == null) { return str; } final int endIndex = str.indexOf(delimiterOfExclusiveEndIndex); if (endIndex < 0) { return str; } return replace(str, 0, endIndex, replacement); } // Remove // ----------------------------------------------------------------------- /** *

* Removes a substring only if it is at the beginning of a source string, * otherwise returns the source string. *

* *

* A {@code null} source string will return {@code null}. An empty ("") * source string will return the empty string. A {@code null} search string * will return the source string. *

* *
     * Strings.removeStart(null, *)      = null
     * Strings.removeStart("", *)        = ""
     * Strings.removeStart(*, null)      = *
     * Strings.removeStart("www.domain.com", "www.")   = "domain.com"
     * Strings.removeStart("domain.com", "www.")       = "domain.com"
     * Strings.removeStart("www.domain.com", "domain") = "www.domain.com"
     * Strings.removeStart("abc", "")    = "abc"
     * 
* * @param str * the source String to search, may be null * @param removeStr * the String to search for and remove, may be null * @return * {@code null} String input */ public static String removeStart(final String str, final String removeStr) { if (isEmpty(str) || isEmpty(removeStr)) { return str; } if (str.startsWith(removeStr)) { return str.substring(removeStr.length()); } return str; } /** *

* Case-insensitive removal of a substring if it is at the beginning of a * source string, otherwise returns the source string. *

* *

* A {@code null} source string will return {@code null}. An empty ("") * source string will return the empty string. A {@code null} search string * will return the source string. *

* *
     * Strings.removeStartIgnoreCase(null, *)      = null
     * Strings.removeStartIgnoreCase("", *)        = ""
     * Strings.removeStartIgnoreCase(*, null)      = *
     * Strings.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
     * Strings.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
     * Strings.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
     * Strings.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
     * Strings.removeStartIgnoreCase("abc", "")    = "abc"
     * 
* * @param str * the source String to search, may be null * @param removeStr * the String to search for (case insensitive) and remove, may be * null * @return the specified String if it's {@code null} or empty, or removal String is {@code null} or empty. */ public static String removeStartIgnoreCase(final String str, final String removeStr) { if (isEmpty(str) || isEmpty(removeStr)) { return str; } if (startsWithIgnoreCase(str, removeStr)) { return str.substring(removeStr.length()); } return str; } /** *

* Removes a substring only if it is at the end of a source string, * otherwise returns the source string. *

* *

* A {@code null} source string will return {@code null}. An empty ("") * source string will return the empty string. A {@code null} search string * will return the source string. *

* *
     * Strings.removeEnd(null, *)      = null
     * Strings.removeEnd("", *)        = ""
     * Strings.removeEnd(*, null)      = *
     * Strings.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
     * Strings.removeEnd("www.domain.com", ".com")   = "www.domain"
     * Strings.removeEnd("www.domain.com", "domain") = "www.domain.com"
     * Strings.removeEnd("abc", "")    = "abc"
     * 
* * @param str * the source String to search, may be null * @param removeStr * the String to search for and remove, may be null * @return the specified String if it's {@code null} or empty, or removal String is {@code null} or empty. */ public static String removeEnd(final String str, final String removeStr) { if (isEmpty(str) || isEmpty(removeStr)) { return str; } if (str.endsWith(removeStr)) { return str.substring(0, str.length() - removeStr.length()); } return str; } /** *

* Case-insensitive removal of a substring if it is at the end of a source * string, otherwise returns the source string. *

* *

* A {@code null} source string will return {@code null}. An empty ("") * source string will return the empty string. A {@code null} search string * will return the source string. *

* *
     * Strings.removeEndIgnoreCase(null, *)      = null
     * Strings.removeEndIgnoreCase("", *)        = ""
     * Strings.removeEndIgnoreCase(*, null)      = *
     * Strings.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
     * Strings.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
     * Strings.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
     * Strings.removeEndIgnoreCase("abc", "")    = "abc"
     * Strings.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
     * Strings.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
     * 
* * @param str * the source String to search, may be null * @param removeStr * the String to search for (case insensitive) and remove, may be * null * @return the specified String if it's {@code null} or empty, or removal String is {@code null} or empty. */ public static String removeEndIgnoreCase(final String str, final String removeStr) { if (isEmpty(str) || isEmpty(removeStr)) { return str; } if (endsWithIgnoreCase(str, removeStr)) { return str.substring(0, str.length() - removeStr.length()); } return str; } /** *

* Removes all occurrences of a character from within the source string. *

* *

* A {@code null} source string will return {@code null}. An empty ("") * source string will return the empty string. *

* *
     * Strings.remove(null, *)       = null
     * Strings.remove("", *)         = ""
     * Strings.remove("queued", 'u') = "qeed"
     * Strings.remove("queued", 'z') = "queued"
     * 
* * @param str * the source String to search, may be null * @param removeChar * the char to search for and remove, may be null * @return the specified String if it's {@code null} or empty. */ public static String removeAll(final String str, final char removeChar) { return removeAll(str, 0, removeChar); } /** * Removes all occurrences of a specified character from the input string, starting from a specified index. * * @param str The input string where the removal should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the removal. It should be a non-negative integer. * @param removeChar The character to be removed. * @return A new string with all occurrences of the specified character removed, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the character is not found, the input string is returned unchanged. */ public static String removeAll(final String str, final int fromIndex, final char removeChar) { // N.checkIndex(fromIndex, N.len(str)); if (str == null || str.isEmpty()) { return str; } final int index = str.indexOf(removeChar, fromIndex); if (index == N.INDEX_NOT_FOUND) { return str; } else { final char[] cbuf = new char[str.length()]; if (index > 0) { str.getChars(0, index, cbuf, 0); } int count = index; char ch = 0; for (int i = index + 1, len = str.length(); i < len; i++) { ch = str.charAt(i); if (ch != removeChar) { cbuf[count++] = ch; } } return count == cbuf.length ? str : new String(cbuf, 0, count); } } /** *

* Removes all occurrences of a substring from within the source string. *

* *

* A {@code null} source string will return {@code null}. An empty ("") * source string will return the empty string. A {@code null} remove string * will return the source string. An empty ("") remove string will return * the source string. *

* *
     * Strings.removeAll(null, *)        = null
     * Strings.removeAll("", *)          = ""
     * Strings.removeAll(*, null)        = *
     * Strings.removeAll(*, "")          = *
     * Strings.removeAll("queued", "ue") = "qd"
     * Strings.removeAll("queued", "zz") = "queued"
     * 
* * @param str * the source String to search, may be null * @param removeStr * the String to search for and remove, may be null * @return the specified String if it's {@code null} or empty. */ public static String removeAll(final String str, final String removeStr) { return removeAll(str, 0, removeStr); } /** * Removes all occurrences of a specified string from the input string, starting from a specified index. * * @param str The input string where the removal should occur. It can be {@code null} or empty. * @param fromIndex The index from which to start the removal. It should be a non-negative integer. * @param removeStr The string to be removed. It can be {@code null} or empty. * @return A new string with all occurrences of the specified string removed, starting from the specified index. * If the input string is {@code null}, the method returns {@code null}. If the input string is empty, or the string to be removed is not found, the input string is returned unchanged. */ public static String removeAll(final String str, final int fromIndex, final String removeStr) { // N.checkIndex(fromIndex, N.len(str)); if (isEmpty(str) || isEmpty(removeStr)) { return str; } return replace(str, fromIndex, removeStr, EMPTY_STRING, -1); } /** * Removes each substring of the source String that matches the given * regular expression using the DOTALL option. * * @param source * the source string * @param regex * the regular expression to which this string is to be matched * @return The resulting {@code String} * @see String#replaceAll(String, String) * @see Pattern#DOTALL */ public static String removePattern(final String source, final String regex) { return replacePattern(source, regex, EMPTY_STRING); } /** * Splits the given string into an array of substrings, using the specified delimiter character. * * @param str The string to be split. * @param delimiter The character used as the delimiter for splitting the string. * @return An array of substrings derived from the input string, split based on the delimiter character. * If the input string is {@code null} or empty, the method will return an empty String array. */ public static String[] split(final String str, final char delimiter) { if (isEmpty(str)) { return N.EMPTY_STRING_ARRAY; } // final Splitter splitter = splitterPool.get(delimiter); // // return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings() : splitter).splitToArray(str); return splitWorker(str, delimiter, Integer.MAX_VALUE, false, false); } /** * Splits the given string into an array of substrings, using the specified delimiter character. * If the trim parameter is {@code true}, it trims leading and trailing whitespace from each substring. * * @param str The string to be split. * @param delimiter The character used as the delimiter for splitting the string. * @param trim A boolean that determines whether to trim leading and trailing whitespace from each substring. * @return An array of substrings derived from the input string, split based on the delimiter character and optionally trimmed. * If the input string is {@code null} or empty, the method will return an empty String array. */ public static String[] split(final String str, final char delimiter, final boolean trim) { if (isEmpty(str)) { return N.EMPTY_STRING_ARRAY; } // if (trim) { // final Splitter splitter = trimSplitterPool.get(delimiter); // return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings().trim(trim) : splitter).splitToArray(str); // } else { // return split(str, delimiter); // } return splitWorker(str, delimiter, Integer.MAX_VALUE, trim, false); } /** * Splits the given string into an array of substrings, using the specified delimiter string. * * @param str The string to be split. * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @return An array of substrings derived from the input string, split based on the delimiter string. * If the input string is {@code null} or empty, the method will return an empty String array. */ public static String[] split(final String str, final String delimiter) { if (isEmpty(str)) { return N.EMPTY_STRING_ARRAY; } // final Splitter splitter = splitterPool.get(delimiter); // // return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings() : splitter).splitToArray(str); return splitWorker(str, delimiter, Integer.MAX_VALUE, false, false); } /** * Splits the given string into an array of substrings, using the specified delimiter string. * If the trim parameter is {@code true}, it trims leading and trailing whitespace from each substring. * * @param str The string to be split. * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @param trim A boolean that determines whether to trim leading and trailing whitespace from each substring. * @return An array of substrings derived from the input string, split based on the delimiter string and optionally trimmed. * If the input string is {@code null} or empty, the method will return an empty String array. */ public static String[] split(final String str, final String delimiter, final boolean trim) { if (isEmpty(str)) { return N.EMPTY_STRING_ARRAY; } // if (trim) { // final Splitter splitter = trimSplitterPool.get(delimiter); // return (splitter == null ? Splitter.with(delimiter).omitEmptyStrings().trim(trim) : splitter).splitToArray(str); // } else { // return split(str, delimiter); // } return splitWorker(str, delimiter, Integer.MAX_VALUE, trim, false); } /** * Splits the given string into an array of substrings, using the specified delimiter string. * The split operation will stop after reaching the specified maximum limit of substrings. * * @param str The string to be split. * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @param max The maximum number of substrings to be included in the resulting array. * If the string contains more delimiters, the last substring will contain all remaining text. * @return An array of substrings derived from the input string, split based on the delimiter string. * If the input string is {@code null} or empty, the method will return an empty String array. * @throws IllegalArgumentException if the max parameter is not a positive integer. */ public static String[] split(final String str, final String delimiter, final int max) throws IllegalArgumentException { N.checkArgPositive(max, cs.max); if (isEmpty(str)) { return N.EMPTY_STRING_ARRAY; } if (max == 1) { return new String[] { str }; } // return Splitter.with(delimiter).omitEmptyStrings().limit(max).splitToArray(str); return splitWorker(str, delimiter, max, false, false); } /** * Splits the given string into an array of substrings, using the specified delimiter string. * The split operation will stop after reaching the specified maximum limit of substrings. * If the trim parameter is {@code true}, it trims leading and trailing whitespace from each substring. * * @param str The string to be split. * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @param max The maximum number of substrings to be included in the resulting array. * If the string contains more delimiters, the last substring will contain all remaining text. * @param trim A boolean that determines whether to trim leading and trailing whitespace from each substring. * @return An array of substrings derived from the input string, split based on the delimiter string, limited by the max parameter and optionally trimmed. * If the input string is {@code null} or empty, the method will return an empty String array. * @throws IllegalArgumentException if the max parameter is not a positive integer. */ public static String[] split(final String str, final String delimiter, final int max, final boolean trim) throws IllegalArgumentException { N.checkArgPositive(max, cs.max); if (isEmpty(str)) { return N.EMPTY_STRING_ARRAY; } if (max == 1) { return new String[] { trim ? str.trim() : str }; } // return Splitter.with(delimiter).omitEmptyStrings().trim(trim).limit(max).splitToArray(str); return splitWorker(str, delimiter, max, trim, false); } /** * Splits the provided text into an array, separator specified, * preserving all tokens, including empty tokens created by adjacent * separators. This is an alternative to using StringTokenizer. * *

The separator is not included in the returned String array. * Adjacent separators are treated as separators for empty tokens. * For more control over the split use the StrTokenizer class.

* *

An empty String array {@code []} will be returned if the input string {@code null}.

*

A String array with single empty String: {@code [""]} will be returned if the input string is empty.

* *
     * Strings.splitPreserveAllTokens(null, *)         = []
     * Strings.splitPreserveAllTokens("", *)           = [""]
     * Strings.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
     * Strings.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
     * Strings.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
     * Strings.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
     * Strings.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
     * Strings.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
     * Strings.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
     * Strings.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
     * Strings.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
     * Strings.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
     * 
* * @param str the String to parse, may be {@code null} * @param delimiter the character used as the delimite * @return an array of parsed Strings. An empty String array {@code []} will be returned if the input string {@code null}, * or a String array with single empty String: {@code [""]} will be returned if the input string is empty. */ public static String[] splitPreserveAllTokens(final String str, final char delimiter) { if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { EMPTY_STRING }; } // final Splitter splitter = preserveSplitterPool.get(delimiter); // // return (splitter == null ? Splitter.with(delimiter) : splitter).splitToArray(str); return splitWorker(str, delimiter, Integer.MAX_VALUE, false, true); } /** * Splits the provided text into an array, separator specified, * preserving all tokens, including empty tokens created by adjacent * separators. This is an alternative to using StringTokenizer. * *

The separator is not included in the returned String array. * Adjacent separators are treated as separators for empty tokens. * For more control over the split use the StrTokenizer class.

* *

An empty String array {@code []} will be returned if the input string {@code null}.

*

A String array with single empty String: {@code [""]} will be returned if the input string is empty.

* * @param str the String to parse, may be {@code null} * @param delimiter the character used as the delimiter * @param trim If {@code true}, leading and trailing whitespace is removed from each substring. * @return an array of parsed Strings. An empty String array {@code []} will be returned if the input string {@code null}, * or a String array with single empty String: {@code [""]} will be returned if the input string is empty. */ public static String[] splitPreserveAllTokens(final String str, final char delimiter, final boolean trim) { if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { EMPTY_STRING }; } // if (trim) { // final Splitter splitter = trimPreserveSplitterPool.get(delimiter); // return (splitter == null ? Splitter.with(delimiter).trim(trim) : splitter).splitToArray(str); // } else { // return splitPreserveAllTokens(str, delimiter); // } return splitWorker(str, delimiter, Integer.MAX_VALUE, trim, true); } /** * Splits the provided text into an array, separators specified, * preserving all tokens, including empty tokens created by adjacent * separators. This is an alternative to using StringTokenizer. * *

The separator is not included in the returned String array. * Adjacent separators are treated as separators for empty tokens. * For more control over the split use the StrTokenizer class.

* *

A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.

* *

An empty String array {@code []} will be returned if the input string {@code null}.

*

A String array with single empty String: {@code [""]} will be returned if the input string is empty.

* *
     * Strings.splitPreserveAllTokens(null, *)           = []
     * Strings.splitPreserveAllTokens("", *)             = [""]
     * Strings.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
     * Strings.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
     * Strings.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
     * Strings.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
     * Strings.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
     * Strings.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
     * Strings.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
     * Strings.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
     * Strings.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
     * Strings.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
     * 
* * @param str the String to parse, may be {@code null} * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @return an array of parsed Strings. An empty String array {@code []} will be returned if the input string {@code null}, * or a String array with single empty String: {@code [""]} will be returned if the input string is empty. */ public static String[] splitPreserveAllTokens(final String str, final String delimiter) { if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { EMPTY_STRING }; } // final Splitter splitter = preserveSplitterPool.get(delimiter); // // return (splitter == null ? Splitter.with(delimiter) : splitter).splitToArray(str); return splitWorker(str, delimiter, Integer.MAX_VALUE, false, true); } /** * Splits the provided text into an array, separators specified, * preserving all tokens, including empty tokens created by adjacent * separators. This is an alternative to using StringTokenizer. * *

The separator is not included in the returned String array. * Adjacent separators are treated as separators for empty tokens. * For more control over the split use the StrTokenizer class.

* *

A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.

* *

An empty String array {@code []} will be returned if the input string {@code null}.

*

A String array with single empty String: {@code [""]} will be returned if the input string is empty.

* * * @param str the String to parse, may be {@code null} * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @param trim If {@code true}, leading and trailing whitespace is removed from each substring. * @return an array of parsed Strings. An empty String array {@code []} will be returned if the input string {@code null}, * or a String array with single empty String: {@code [""]} will be returned if the input string is empty. */ public static String[] splitPreserveAllTokens(final String str, final String delimiter, final boolean trim) { if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { EMPTY_STRING }; } // if (trim) { // final Splitter splitter = trimPreserveSplitterPool.get(delimiter); // return (splitter == null ? Splitter.with(delimiter).trim(trim) : splitter).splitToArray(str); // } else { // return splitPreserveAllTokens(str, delimiter); // } return splitWorker(str, delimiter, Integer.MAX_VALUE, trim, true); } /** * Splits the provided text into an array with a maximum length, * separators specified. * *

The separator is not included in the returned String array. * Adjacent separators are treated as one separator.

* *

A {@code null} input String returns {@code null}. * A {@code null} separatorChars splits on whitespace.

* *

If more than {@code max} delimited substrings are found, the last * returned string includes all characters after the first {@code max - 1} * returned strings (including separator characters).

* *

A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.

* *

An empty String array {@code []} will be returned if the input string {@code null}.

*

A String array with single empty String: {@code [""]} will be returned if the input string is empty.

* * * @param str the String to parse, may be {@code null} * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @param max The maximum number of substrings to be included in the resulting array. * @return an array of parsed Strings. An empty String array {@code []} will be returned if the input string {@code null}, * or a String array with single empty String: {@code [""]} will be returned if the input string is empty. * @throws IllegalArgumentException if the max parameter is not a positive integer. */ public static String[] splitPreserveAllTokens(final String str, final String delimiter, final int max) throws IllegalArgumentException { N.checkArgPositive(max, cs.max); if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { EMPTY_STRING }; } if (max == 1) { return new String[] { str }; } // return Splitter.with(delimiter).limit(max).splitToArray(str); return splitWorker(str, delimiter, max, false, true); } /** * Splits the provided text into an array with a maximum length, * separators specified. * *

The separator is not included in the returned String array. * Adjacent separators are treated as one separator.

* *

A {@code null} input String returns {@code null}. * A {@code null} separatorChars splits on whitespace.

* *

If more than {@code max} delimited substrings are found, the last * returned string includes all characters after the first {@code max - 1} * returned strings (including separator characters).

* *

A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.

* *

An empty String array {@code []} will be returned if the input string {@code null}.

*

A String array with single empty String: {@code [""]} will be returned if the input string is empty.

* * * @param str the String to parse, may be {@code null} * @param delimiter The string used as the delimiter for splitting the string. {@code null} for splitting on whitespace. * @param max The maximum number of substrings to be included in the resulting array. * @param trim If {@code true}, leading and trailing whitespace is removed from each substring. * @return an array of parsed Strings. An empty String array {@code []} will be returned if the input string {@code null}, * or a String array with single empty String: {@code [""]} will be returned if the input string is empty. * @throws IllegalArgumentException if the max parameter is not a positive integer. */ public static String[] splitPreserveAllTokens(final String str, final String delimiter, final int max, final boolean trim) throws IllegalArgumentException { N.checkArgPositive(max, cs.max); if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { EMPTY_STRING }; } if (max == 1) { return new String[] { trim ? str.trim() : str }; } // return Splitter.with(delimiter).trim(trim).limit(max).splitToArray(str); return splitWorker(str, delimiter, max, trim, true); } // Copied from Apache Commons Lang 3.17.0 under Apache License 2.0 private static String[] splitWorker(final String str, final char delimiter, final int max, final boolean trim, final boolean preserveAllTokens) throws IllegalArgumentException { N.checkArgPositive(max, cs.max); if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return preserveAllTokens ? new String[] { EMPTY_STRING } : N.EMPTY_STRING_ARRAY; } final int len = str.length(); final List substrs = new ArrayList<>(); int sizePlus1 = 1; int i = 0; int start = 0; boolean match = false; boolean lastMatch = false; while (i < len) { if (str.charAt(i) == delimiter) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } substrs.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } if (match || preserveAllTokens && lastMatch) { substrs.add(str.substring(start, i)); } final String[] ret = substrs.toArray(N.EMPTY_STRING_ARRAY); if (trim) { trim(ret); } return ret; } // Copied from Apache Commons Lang 3.17.0 under Apache License 2.0 private static String[] splitWorker(final String str, final String delimiter, final int max, final boolean trim, final boolean preserveAllTokens) throws IllegalArgumentException { N.checkArgPositive(max, cs.max); if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return preserveAllTokens ? new String[] { EMPTY_STRING } : N.EMPTY_STRING_ARRAY; } if (N.len(delimiter) == 1) { return splitWorker(str, delimiter.charAt(0), max, trim, preserveAllTokens); } final int len = str.length(); final List substrs = new ArrayList<>(); int sizePlus1 = 1; int i = 0; int start = 0; boolean match = false; boolean lastMatch = false; if (delimiter == null) { // Null separator means use whitespace while (i < len) { if (Character.isWhitespace(str.charAt(i))) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } substrs.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } else { // standard case while (i < len) { if (delimiter.indexOf(str.charAt(i)) >= 0) { if (match || preserveAllTokens) { lastMatch = true; if (sizePlus1++ == max) { i = len; lastMatch = false; } substrs.add(str.substring(start, i)); match = false; } start = ++i; continue; } lastMatch = false; match = true; i++; } } if (match || preserveAllTokens && lastMatch) { substrs.add(str.substring(start, i)); } final String[] ret = substrs.toArray(N.EMPTY_STRING_ARRAY); if (trim) { trim(ret); } return ret; } /** * Splits the given string into an array of substrings, each of which is a line of text from the original string. * The string is split at line terminators, which can be the carriage return character ('\r'), the newline character ('\n'), or the carriage return followed immediately by the newline character. * * @param str The string to be split. If it's {@code null}, the method will return an empty String array. * @return An array of substrings derived from the input string, each of which is a line of text. * If the input string is {@code null}, return an empty String array. If the input string is empty, return an String array with one empty String inside. */ public static String[] splitToLines(final String str) { if (str == null) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { Strings.EMPTY_STRING }; } return lineSplitter.splitToArray(str); } /** * Splits the given string into an array of substrings, each of which is a line of text from the original string. * The string is split at line terminators, which can be the carriage return character ('\r'), the newline character ('\n'), or the carriage return followed immediately by the newline character. * If the trim parameter is {@code true}, leading and trailing whitespace is removed from each line of text. * If the omitEmptyLines parameter is {@code true}, empty lines (after trimming, if the trim parameter is true) are not included in the resulting array. * * @param str The string to be split. * @param trim A boolean that determines whether to trim leading and trailing whitespace from each line of text. * @param omitEmptyLines A boolean that determines whether to omit empty lines from the resulting array. * @return An array of substrings derived from the input string, each of which is a line of text, optionally trimmed and with empty lines optionally omitted. * If the input string is {@code null} or {@code str.length() == 0 && omitEmptyLines}, return an empty String array. If the input string is empty, return an String array with one empty String inside. */ public static String[] splitToLines(final String str, final boolean trim, final boolean omitEmptyLines) { if (str == null || (str.isEmpty() && omitEmptyLines)) { return N.EMPTY_STRING_ARRAY; } else if (str.isEmpty()) { return new String[] { Strings.EMPTY_STRING }; } if (trim) { if (omitEmptyLines) { return trimAndOmitEmptyLinesLineSplitter.splitToArray(str); } else { return trimLineSplitter.splitToArray(str); } } else if (omitEmptyLines) { return omitEmptyLinesLineSplitter.splitToArray(str); } else { return lineSplitter.splitToArray(str); } } // ----------------------------------------------------------------------- /** *

* Removes space characters (char <= 32) from both ends of this String, * handling {@code null} by returning {@code null}. *

* *

* The String is trimmed using {@link String#trim()}. Trim removes start and * end characters <= 32. To strip whitespace use {@link #strip(String)}. *

* *

* To trim your choice of characters, use the {@link #strip(String, String)} * methods. *

* *
     * Strings.trim(null)          = null
     * Strings.trim("")            = ""
     * Strings.trim("     ")       = ""
     * Strings.trim("abc")         = "abc"
     * Strings.trim("    abc    ") = "abc"
     * 
* * @param str * the String to be trimmed, may be null * @return */ public static String trim(final String str) { return isEmpty(str) || (str.charAt(0) != ' ' && str.charAt(str.length() - 1) != ' ') ? str : str.trim(); } /** * Trims leading and trailing space characters from each string in the provided array. * This method uses {@link String#trim()} to remove space characters. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be trimmed. Each string in the array will be updated in-place. */ public static void trim(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = trim(strs[i]); } } /** *

* Removes space characters (char <= 32) from both ends of this String * returning {@code null} if the String is empty ("") after the trim or if * it is {@code null}. * *

* The String is trimmed using {@link String#trim()}. Trim removes start and * end characters <= 32. To strip whitespace use * {@link #stripToNull(String)}. *

* *
     * Strings.trimToNull(null)          = null
     * Strings.trimToNull("")            = null
     * Strings.trimToNull("     ")       = null
     * Strings.trimToNull("abc")         = "abc"
     * Strings.trimToNull("    abc    ") = "abc"
     * 
* * @param str * the String to be trimmed, may be null * @return * {@code null} String input */ public static String trimToNull(String str) { str = trim(str); return isEmpty(str) ? null : str; } /** * Trims leading and trailing whitespace from each string in the provided array and sets the string to {@code null} if it is empty after trimming. * This method uses {@link String#trim()} to remove whitespace. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be trimmed. Each string in the array will be updated in-place. */ public static void trimToNull(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = trimToNull(strs[i]); } } /** *

* Removes control characters (char <= 32) from both ends of this String * returning an empty String ("") if the String is empty ("") after the trim * or if it is {@code null}. * *

* The String is trimmed using {@link String#trim()}. Trim removes start and * end characters <= 32. To strip whitespace use * {@link #stripToEmpty(String)}. *

* *
     * Strings.trimToEmpty(null)          = ""
     * Strings.trimToEmpty("")            = ""
     * Strings.trimToEmpty("     ")       = ""
     * Strings.trimToEmpty("abc")         = "abc"
     * Strings.trimToEmpty("    abc    ") = "abc"
     * 
* * @param str * the String to be trimmed, may be null * @return */ public static String trimToEmpty(final String str) { return isEmpty(str) ? EMPTY_STRING : str.trim(); } /** * Trims leading and trailing whitespace from each string in the provided array. * If a string becomes {@code null} after trimming, it is set to empty. * This method uses {@link String#trim()} to remove whitespace. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be trimmed. Each string in the array will be updated in-place. */ public static void trimToEmpty(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = trimToEmpty(strs[i]); } } // Stripping // ----------------------------------------------------------------------- /** *

* Strips whitespace from the start and end of a String. *

* *

* This is similar to {@link #trim(String)} but removes whitespace. * Whitespace is defined by {@link Character#isWhitespace(char)}. *

* *

* A {@code null} input String returns {@code null}. *

* *
     * Strings.strip(null)     = null
     * Strings.strip("")       = ""
     * Strings.strip("   ")    = ""
     * Strings.strip("abc")    = "abc"
     * Strings.strip("  abc")  = "abc"
     * Strings.strip("abc  ")  = "abc"
     * Strings.strip(" abc ")  = "abc"
     * Strings.strip(" ab c ") = "ab c"
     * 
* * @param str * the String to remove whitespace from, may be null * @return */ public static String strip(final String str) { return strip(str, null); } /** * Strips whitespace from the start and end of each string in the provided array. * This method uses {@link #strip(String)} to remove whitespace. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. */ public static void strip(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = strip(strs[i]); } } /** *

* Strips whitespace from the start and end of a String returning * {@code null} if the String is empty ("") after the strip. *

* *

* This is similar to {@link #trimToNull(String)} but removes whitespace. * Whitespace is defined by {@link Character#isWhitespace(char)}. *

* *
     * Strings.stripToNull(null)     = null
     * Strings.stripToNull("")       = null
     * Strings.stripToNull("   ")    = null
     * Strings.stripToNull("abc")    = "abc"
     * Strings.stripToNull("  abc")  = "abc"
     * Strings.stripToNull("abc  ")  = "abc"
     * Strings.stripToNull(" abc ")  = "abc"
     * Strings.stripToNull(" ab c ") = "ab c"
     * 
* * @param str * the String to be stripped, may be null * @return * String input */ public static String stripToNull(String str) { str = strip(str, null); return isEmpty(str) ? null : str; } /** * Strips whitespace from the start and end of each string in the provided array and sets the string to {@code null} if it is empty after stripping. * This method uses {@link #strip(String)} to remove whitespace. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. */ public static void stripToNull(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = stripToNull(strs[i]); } } /** *

* Strips whitespace from the start and end of a String returning an empty * String if {@code null} input. *

* *

* This is similar to {@link #trimToEmpty(String)} but removes whitespace. * Whitespace is defined by {@link Character#isWhitespace(char)}. *

* *
     * Strings.stripToEmpty(null)     = ""
     * Strings.stripToEmpty("")       = ""
     * Strings.stripToEmpty("   ")    = ""
     * Strings.stripToEmpty("abc")    = "abc"
     * Strings.stripToEmpty("  abc")  = "abc"
     * Strings.stripToEmpty("abc  ")  = "abc"
     * Strings.stripToEmpty(" abc ")  = "abc"
     * Strings.stripToEmpty(" ab c ") = "ab c"
     * 
* * @param str * the String to be stripped, may be null * @return */ public static String stripToEmpty(final String str) { return isEmpty(str) ? EMPTY_STRING : strip(str, null); } /** * Strips leading and trailing whitespace from each string in the provided array. * If a string becomes {@code null} after stripping, it is set to an empty string. * This method uses {@link #strip(String)} to remove whitespace. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. */ public static void stripToEmpty(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = stripToEmpty(strs[i]); } } /** *

* Strips any of a set of characters from the start and end of a String. * This is similar to {@link String#trim()} but allows the characters to be * stripped to be controlled. *

* *

* A {@code null} input String returns {@code null}. An empty string ("") * input returns the empty string. *

* *

* If the stripChars String is {@code null}, whitespace is stripped as * defined by {@link Character#isWhitespace(char)}. Alternatively use * {@link #strip(String)}. *

* *
     * Strings.strip(null, *)          = null
     * Strings.strip("", *)            = ""
     * Strings.strip("abc", null)      = "abc"
     * Strings.strip("  abc", null)    = "abc"
     * Strings.strip("abc  ", null)    = "abc"
     * Strings.strip(" abc ", null)    = "abc"
     * Strings.strip("  abcyx", "xyz") = "  abc"
     * 
* * @param str * the String to remove characters from, may be null * @param stripChars * the characters to remove, {@code null} treated as whitespace * @return the specified String if it's {@code null} or empty. */ public static String strip(final String str, final String stripChars) { if (str == null || str.isEmpty()) { return str; } return stripEnd(stripStart(str, stripChars), stripChars); } /** * Strips the specified characters from the start and end of each string in the provided array. * This method uses {@link #strip(String, String)} to remove the specified characters. * If the input array is {@code null} or empty, or the stripChars is {@code null}, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. * @param stripChars The set of characters to be stripped from the strings. If {@code null}, the method behaves as {@link #strip(String)}. */ public static void strip(final String[] strs, final String stripChars) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = strip(strs[i], stripChars); } } /** *

* Strips any of a set of characters from the start of a String. *

* *

* A {@code null} input String returns {@code null}. An empty string ("") * input returns the empty string. *

* *

* If the stripChars String is {@code null}, whitespace is stripped as * defined by {@link Character#isWhitespace(char)}. *

* *
     * Strings.stripStart(null, *)          = null
     * Strings.stripStart("", *)            = ""
     * Strings.stripStart("abc", "")        = "abc"
     * Strings.stripStart("abc", null)      = "abc"
     * Strings.stripStart("  abc", null)    = "abc"
     * Strings.stripStart("abc  ", null)    = "abc  "
     * Strings.stripStart(" abc ", null)    = "abc "
     * Strings.stripStart("yxabc  ", "xyz") = "abc  "
     * 
* * @param str * the String to remove characters from, may be null * @param stripChars * the characters to remove, {@code null} treated as whitespace * @return the specified String if it's {@code null} or empty. */ public static String stripStart(final String str, final String stripChars) { if (isEmpty(str) || (stripChars != null && stripChars.isEmpty())) { return str; } final int strLen = str.length(); int start = 0; if (stripChars == null) { while (start != strLen && Character.isWhitespace(str.charAt(start))) { start++; } } else { while (start != strLen && stripChars.indexOf(str.charAt(start)) != N.INDEX_NOT_FOUND) { start++; } } return start == 0 ? str : str.substring(start); } /** * Strips the specified characters from the start of each string in the provided array. * This method uses {@link #stripStart(String, String)} to remove the specified characters. * If the input array is {@code null} or empty, or the stripChars is {@code null}, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. * @param stripChars The set of characters to be stripped from the start of the strings. If {@code null}, the method behaves as {@link #stripStart(String, String)}. * @see #stripStart(String, String) */ public static void stripStart(final String[] strs, final String stripChars) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = stripStart(strs[i], stripChars); } } /** *

* Strips any of a set of characters from the end of a String. *

* *

* A {@code null} input String returns {@code null}. An empty string ("") * input returns the empty string. *

* *

* If the stripChars String is {@code null}, whitespace is stripped as * defined by {@link Character#isWhitespace(char)}. *

* *
     * Strings.stripEnd(null, *)          = null
     * Strings.stripEnd("", *)            = ""
     * Strings.stripEnd("abc", "")        = "abc"
     * Strings.stripEnd("abc", null)      = "abc"
     * Strings.stripEnd("  abc", null)    = "  abc"
     * Strings.stripEnd("abc  ", null)    = "abc"
     * Strings.stripEnd(" abc ", null)    = " abc"
     * Strings.stripEnd("  abcyx", "xyz") = "  abc"
     * Strings.stripEnd("120.00", ".0")   = "12"
     * 
* * @param str * the String to remove characters from, may be null * @param stripChars * the set of characters to remove, {@code null} treated as whitespace * @return the specified String if it's {@code null} or empty. */ public static String stripEnd(final String str, final String stripChars) { if (isEmpty(str) || (stripChars != null && stripChars.isEmpty())) { return str; } int end = str.length(); if (stripChars == null) { while (end > 0 && Character.isWhitespace(str.charAt(end - 1))) { end--; } } else { while (end > 0 && stripChars.indexOf(str.charAt(end - 1)) != N.INDEX_NOT_FOUND) { end--; } } return end == str.length() ? str : str.substring(0, end); } /** * Strips the specified characters from the end of each string in the provided array. * This method uses {@link #stripEnd(String, String)} to remove the specified characters. * If the input array is {@code null} or empty, or the stripChars is {@code null}, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. * @param stripChars The set of characters to be stripped from the end of the strings. If {@code null}, the method behaves as {@link #stripEnd(String, String)}. * @see #stripEnd(String, String) */ public static void stripEnd(final String[] strs, final String stripChars) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = stripEnd(strs[i], stripChars); } } /** *

* Removes diacritics (~= accents) from a string. The case will not be * altered. *

*

* For instance, à will be replaced by 'a'. *

*

* Note that ligatures will be left as is. *

* *
     * Strings.stripAccents(null)                = null
     * Strings.stripAccents("")                  = ""
     * Strings.stripAccents("control")           = "control"
     * Strings.stripAccents("éclair")     = "eclair"
     * 
* * @param str * @return */ // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented // characters by their unaccented equivalent (and uncommitted bug fix: // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907). @MayReturnNull public static String stripAccents(final String str) { if (str == null) { return null; } final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(str, Normalizer.Form.NFD)); convertRemainingAccentCharacters(decomposed); // Note that this doesn't correctly remove ligatures... return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY_STRING); } /** * Pattern used in {@link #stripAccents(String)}. */ private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$ private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { char ch = 0; for (int i = 0; i < decomposed.length(); i++) { ch = decomposed.charAt(i); if (ch == '\u0141') { decomposed.setCharAt(i, 'L'); } else if (ch == '\u0142') { decomposed.setCharAt(i, 'l'); } } } /** * Strips accents from each string in the provided array. * This method uses {@link #stripAccents(String)} to remove accents. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be stripped. Each string in the array will be updated in-place. */ public static void stripAccents(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = stripAccents(strs[i]); } } // Chomping // ----------------------------------------------------------------------- /** *

* Removes one newline from end of a String if it's there, otherwise leave * it alone. A newline is "{@code \n} ", "{@code \r}", * or "{@code \r\n}". *

* *

* NOTE: This method changed in 2.0. It now more closely matches Perl chomp. *

* *
     * Strings.chomp(null)          = null
     * Strings.chomp("")            = ""
     * Strings.chomp("abc \r")      = "abc "
     * Strings.chomp("abc\n")       = "abc"
     * Strings.chomp("abc\r\n")     = "abc"
     * Strings.chomp("abc\r\n\r\n") = "abc\r\n"
     * Strings.chomp("abc\n\r")     = "abc\n"
     * Strings.chomp("abc\n\rabc")  = "abc\n\rabc"
     * Strings.chomp("\r")          = ""
     * Strings.chomp("\n")          = ""
     * Strings.chomp("\r\n")        = ""
     * 
* * @param str * the String to chomp a newline from, may be null * @return String without newline, {@code null} if {@code null} String input */ public static String chomp(final String str) { if (str == null || str.isEmpty()) { return str; } if (str.length() == 1) { final char ch = str.charAt(0); if (ch == CHAR_CR || ch == CHAR_LF) { return EMPTY_STRING; } return str; } int lastIdx = str.length() - 1; final char last = str.charAt(lastIdx); if (last == CHAR_LF) { if (str.charAt(lastIdx - 1) == CHAR_CR) { lastIdx--; } } else if (last != CHAR_CR) { lastIdx++; } return lastIdx == str.length() ? str : str.substring(0, lastIdx); } /** * Removes one newline from end of each string in the provided array if it's there, otherwise leaves it alone. * A newline is "\n", "\r", or "\r\n". * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be chomped. Each string in the array will be updated in-place. */ public static void chomp(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = chomp(strs[i]); } } // Chopping // ----------------------------------------------------------------------- /** *

* Remove the last character from a String. *

* *

* If the String ends in {@code \r\n}, then remove both of them. *

* *
     * Strings.chop(null)          = null
     * Strings.chop("")            = ""
     * Strings.chop("abc \r")      = "abc "
     * Strings.chop("abc\n")       = "abc"
     * Strings.chop("abc\r\n")     = "abc"
     * Strings.chop("abc")         = "ab"
     * Strings.chop("abc\nabc")    = "abc\nab"
     * Strings.chop("a")           = ""
     * Strings.chop("\r")          = ""
     * Strings.chop("\n")          = ""
     * Strings.chop("\r\n")        = ""
     * 
* * @param str * the String to chop last character from, may be null * @return String without last character, {@code null} if {@code null} String input */ public static String chop(final String str) { if (str == null || str.isEmpty()) { return str; } final int strLen = str.length(); if (strLen < 2) { return EMPTY_STRING; } final int lastIdx = strLen - 1; if (str.charAt(lastIdx) == CHAR_LF && str.charAt(lastIdx - 1) == CHAR_CR) { return str.substring(0, lastIdx - 1); } else { return str.substring(0, lastIdx); } } /** * Removes the last character from each string in the provided array. * If a string in the array ends in "\r\n", both characters are removed. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be chopped. Each string in the array will be updated in-place. */ public static void chop(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = chop(strs[i]); } } /** *

Truncates a String. This will turn * "Now is the time for all good men" into "Now is the time for".

* *

Specifically:

*
    *
  • If {@code str} is less than {@code maxWidth} characters * long, return it.
  • *
  • Else truncate it to {@code substring(str, 0, maxWidth)}.
  • *
  • If {@code maxWidth} is less than {@code 0}, throw an * {@code IllegalArgumentException}.
  • *
  • In no case will it return a String of length greater than * {@code maxWidth}.
  • *
* *
     * Strings.truncate(null, 0)       = null
     * Strings.truncate(null, 2)       = null
     * Strings.truncate("", 4)         = ""
     * Strings.truncate("abcdefg", 4)  = "abcd"
     * Strings.truncate("abcdefg", 6)  = "abcdef"
     * Strings.truncate("abcdefg", 7)  = "abcdefg"
     * Strings.truncate("abcdefg", 8)  = "abcdefg"
     * Strings.truncate("abcdefg", -1) = throws an IllegalArgumentException
     * 
* * @param str the String to truncate, may be null * @param maxWidth maximum length of result String, must be positive * @return truncated String, {@code null} if {@code null} String input * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0} */ public static String truncate(final String str, final int maxWidth) { return truncate(str, 0, maxWidth); } /** *

Truncates a String. This will turn * "Now is the time for all good men" into "is the time for all".

* *

Works like {@code truncate(String, int)}, but allows you to specify * a "left edge" offset. * *

Specifically:

*
    *
  • If {@code str} is less than {@code maxWidth} characters * long, return it.
  • *
  • Else truncate it to {@code substring(str, offset, maxWidth)}.
  • *
  • If {@code maxWidth} is less than {@code 0}, throw an * {@code IllegalArgumentException}.
  • *
  • If {@code offset} is less than {@code 0}, throw an * {@code IllegalArgumentException}.
  • *
  • In no case will it return a String of length greater than * {@code maxWidth}.
  • *
* *
     * Strings.truncate(null, 0, 0) = null
     * Strings.truncate(null, 2, 4) = null
     * Strings.truncate("", 0, 10) = ""
     * Strings.truncate("", 2, 10) = ""
     * Strings.truncate("abcdefghij", 0, 3) = "abc"
     * Strings.truncate("abcdefghij", 5, 6) = "fghij"
     * Strings.truncate("raspberry peach", 10, 15) = "peach"
     * Strings.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
     * Strings.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
     * Strings.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
     * Strings.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
     * Strings.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
     * Strings.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
     * Strings.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
     * Strings.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
     * Strings.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
     * Strings.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
     * Strings.truncate("abcdefghijklmno", 5, 5) = "fghij"
     * Strings.truncate("abcdefghijklmno", 5, 3) = "fgh"
     * Strings.truncate("abcdefghijklmno", 10, 3) = "klm"
     * Strings.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
     * Strings.truncate("abcdefghijklmno", 13, 1) = "n"
     * Strings.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
     * Strings.truncate("abcdefghijklmno", 14, 1) = "o"
     * Strings.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
     * Strings.truncate("abcdefghijklmno", 15, 1) = ""
     * Strings.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
     * Strings.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
     * Strings.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
     * Strings.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
     * 
* * @param str the String to truncate, may be null * @param offset left edge of source String * @param maxWidth maximum length of result String, must be positive * @return truncated String, {@code null} if {@code null} String input * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0} */ @MayReturnNull public static String truncate(final String str, final int offset, final int maxWidth) throws IllegalArgumentException { N.checkArgNotNegative(offset, cs.offset); N.checkArgNotNegative(maxWidth, cs.maxWidth); if (str == null) { return null; } else if (str.length() <= offset || maxWidth == 0) { return EMPTY_STRING; } else if (str.length() - offset <= maxWidth) { return offset == 0 ? str : str.substring(offset); } else { return str.substring(offset, offset + maxWidth); } } /** * Truncates each string in the provided array to the specified maximum width. * If a string in the array has a length less than or equal to the maxWidth, it remains unchanged. * If a string in the array has a length greater than the maxWidth, it is truncated to the maxWidth. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be truncated. Each string in the array will be updated in-place. * @param maxWidth The maximum length for each string. Must be non-negative. * @throws IllegalArgumentException If maxWidth is less than 0. */ public static void truncate(final String[] strs, final int maxWidth) { N.checkArgNotNegative(maxWidth, cs.maxWidth); if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = truncate(strs[i], maxWidth); } } /** * Truncates each string in the provided array to the specified maximum width starting from the given offset. * If a string in the array has a length less than or equal to the maxWidth, it remains unchanged. * If a string in the array has a length greater than the maxWidth, it is truncated to the maxWidth. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be truncated. Each string in the array will be updated in-place. * @param offset The starting index from where the string needs to be truncated. * @param maxWidth The maximum length for each string starting from the offset. Must be non-negative. * @throws IllegalArgumentException If maxWidth or offset is less than 0. */ public static void truncate(final String[] strs, final int offset, final int maxWidth) { N.checkArgNotNegative(offset, cs.offset); N.checkArgNotNegative(maxWidth, cs.maxWidth); if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = truncate(strs[i], offset, maxWidth); } } // Delete // ----------------------------------------------------------------------- /** *

* Deletes all white spaces from a String as defined by * {@link Character#isWhitespace(char)}. *

* *
     * Strings.deleteWhitespace(null)         = null
     * Strings.deleteWhitespace("")           = ""
     * Strings.deleteWhitespace("abc")        = "abc"
     * Strings.deleteWhitespace("   ab  c  ") = "abc"
     * 
* * @param str * the String to delete whitespace from, may be null * @return the specified String if it's {@code null} or empty. */ public static String deleteWhitespace(final String str) { if (str == null || str.isEmpty()) { return str; } final int len = str.length(); final char[] cbuf = new char[len]; int count = 0; char ch = 0; for (int i = 0; i < len; i++) { ch = str.charAt(i); if (!Character.isWhitespace(ch)) { cbuf[count++] = ch; } } return count == cbuf.length ? str : new String(cbuf, 0, count); } /** * Deletes all white spaces from each string in the provided array. * White spaces are determined by {@link Character#isWhitespace(char)}. * If the input array is {@code null} or empty, the method does nothing. * * @param strs The array of strings to be processed. Each string in the array will be updated in-place. */ public static void deleteWhitespace(final String[] strs) { if (N.isEmpty(strs)) { return; } for (int i = 0, len = strs.length; i < len; i++) { strs[i] = deleteWhitespace(strs[i]); } } /** * Appends the specified suffix to the input string if it is not already present at the end of the string. * If the input string is {@code null} or empty, the suffix is returned as is. * * @param str The string to which the suffix should be appended. May be {@code null} or empty. * @param suffix The suffix to append to the string. Must not be empty. * @return The input string with the suffix appended if it was not already present; otherwise, the original string. * @throws IllegalArgumentException If the suffix is empty. */ public static String appendIfMissing(final String str, final String suffix) throws IllegalArgumentException { N.checkArgNotEmpty(suffix, cs.suffix); if (str == null || str.isEmpty()) { return suffix; } else if (str.endsWith(suffix)) { return str; } else { return str + suffix; } } /** * Appends the specified suffix to the input string if it is not already present at the end of the string. * The check for the presence of the suffix is case-insensitive. * If the input string is {@code null} or empty, the suffix is returned as is. * * @param str The string to which the suffix should be appended. May be {@code null} or empty. * @param suffix The suffix to append to the string. Must not be empty. * @return The input string with the suffix appended if it was not already present; otherwise, the original string. * @throws IllegalArgumentException If the suffix is empty. */ public static String appendIfMissingIgnoreCase(final String str, final String suffix) throws IllegalArgumentException { N.checkArgNotEmpty(suffix, cs.suffix); if (str == null || str.isEmpty()) { return suffix; } else if (Strings.endsWithIgnoreCase(str, suffix)) { return str; } else { return str + suffix; } } /** * Prepends the specified prefix to the input string if it is not already present at the start of the string. * If the input string is {@code null} or empty, the prefix is returned as is. * * @param str The string to which the prefix should be prepended. May be {@code null} or empty. * @param prefix The prefix to prepend to the string. Must not be empty. * @return The input string with the prefix prepended if it was not already present; otherwise, the original string. * @throws IllegalArgumentException If the prefix is empty. */ public static String prependIfMissing(final String str, final String prefix) throws IllegalArgumentException { N.checkArgNotEmpty(prefix, cs.prefix); if (str == null || str.isEmpty()) { return prefix; } else if (str.startsWith(prefix)) { return str; } else { return concat(prefix, str); } } /** * Prepends the specified prefix to the input string if it is not already present at the start of the string. * The check for the presence of the prefix is case-insensitive. * If the input string is {@code null} or empty, the prefix is returned as is. * * @param str The string to which the prefix should be prepended. May be {@code null} or empty. * @param prefix The prefix to prepend to the string. Must not be empty. * @return The input string with the prefix prepended if it was not already present; otherwise, the original string. * @throws IllegalArgumentException If the prefix is empty. */ public static String prependIfMissingIgnoreCase(final String str, final String prefix) throws IllegalArgumentException { N.checkArgNotEmpty(prefix, cs.prefix); if (str == null || str.isEmpty()) { return prefix; } else if (Strings.startsWithIgnoreCase(str, prefix)) { return str; } else { return concat(prefix, str); } } /** * Wraps the input string with the specified prefix and suffix if they are not already present. *
  • If the input string is {@code null} or empty, the prefix and suffix are concatenated and returned.
  • *
  • If the input string already starts with the prefix and ends with the suffix, the original string is returned.
  • *
  • Else if the input string already starts with the prefix but not ends with the suffix, then {@code str + prefixSuffix} is returned.
  • *
  • Else if the input string ends with the suffix, then {@code prefixSuffix + str} is returned.
  • *
  • Otherwise, the prefix and suffix are added to the start and end of the string respectively.
  • * * @param str The string to be wrapped. May be {@code null} or empty. * @param prefixSuffix The string to be used as both the prefix and suffix for wrapping. Must not be empty. * @return The input string wrapped with the prefixSuffix at both ends if they were not already present; otherwise, the original string. * @throws IllegalArgumentException If the prefixSuffix is empty. */ public static String wrapIfMissing(final String str, final String prefixSuffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefixSuffix, cs.prefixSuffix); return wrapIfMissing(str, prefixSuffix, prefixSuffix); } /** * Wraps the input string with the specified prefix and suffix if they are not already present. *
  • If the input string is {@code null} or empty, the prefix and suffix are concatenated and returned.
  • *
  • If the input string already starts with the prefix and ends with the suffix, the original string is returned.
  • *
  • Else if the input string already starts with the prefix but not ends with the suffix, then {@code str + suffix} is returned.
  • *
  • Else if the input string ends with the suffix, then {@code prefix + str} is returned.
  • *
  • Otherwise, the prefix and suffix are added to the start and end of the string respectively.
  • * *
         * Strings.wrapIfMissing(null, "[", "]") -> "[]"
         * Strings.wrapIfMissing("", "[", "]") -> "[]"
         * Strings.wrapIfMissing("[", "[", "]") -> "[]"
         * Strings.wrapIfMissing("]", "[", "]") -> "[]"
         * Strings.wrapIfMissing("abc", "[", "]") -> "[abc]"
         * Strings.wrapIfMissing("a", "aa", "aa") -> "aaaaa"
         * Strings.wrapIfMissing("aa", "aa", "aa") -> "aaaa"
         * Strings.wrapIfMissing("aaa", "aa", "aa") -> "aaaaa"
         * Strings.wrapIfMissing("aaaa", "aa", "aa") -> "aaaa"
         * 
    * * @param str The string to be wrapped. May be {@code null} or empty. * @param prefix The string to be used as the prefix for wrapping. Must not be empty. * @param suffix The string to be used as the suffix for wrapping. Must not be empty. * @return The input string wrapped with the prefix and suffix at both ends if they were not already present; otherwise, the original string. * @throws IllegalArgumentException If the prefix or suffix is empty. */ public static String wrapIfMissing(final String str, final String prefix, final String suffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefix, cs.prefix); N.checkArgNotEmpty(prefix, cs.suffix); if (isEmpty(str)) { return concat(prefix, suffix); } else if (str.startsWith(prefix)) { return (str.length() - prefix.length() >= suffix.length() && str.endsWith(suffix)) ? str : concat(str + suffix); } else if (str.endsWith(suffix)) { return concat(prefix, str); } else { return concat(prefix, str, suffix); } } /** * Wraps the input string with the specified prefix and suffix. * If the input string is {@code null}, it will be treated as an empty string. * * @param str The string to be wrapped. May be {@code null}. * @param prefixSuffix The string to be used as both the prefix and suffix for wrapping. Must not be empty. * @return The input string wrapped with the prefixSuffix at both ends. * @throws IllegalArgumentException If the prefixSuffix is empty. */ public static String wrap(final String str, final String prefixSuffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefixSuffix, cs.prefixSuffix); return wrap(str, prefixSuffix, prefixSuffix); } /** * Wraps the input string with the specified prefix and suffix. * If the input string is {@code null}, it will be treated as an empty string. * *
         * Strings.wrap(null, "[", "]") -> "[]"
         * Strings.wrap("", "[", "]") -> "[]"
         * Strings.wrap("[", "[", "]") -> "[[]"
         * Strings.wrap("]", "[", "]") -> "[]]"
         * Strings.wrap("abc", "[", "]") -> "[abc]"
         * Strings.wrap("a", "aa", "aa") -> "aaaaa"
         * Strings.wrap("aa", "aa", "aa") -> "aaaaaa"
         * Strings.wrap("aaa", "aa", "aa") -> "aaaaaaa"
         * 
    * * @param str The string to be wrapped. May be {@code null}. * @param prefix The string to be used as the prefix for wrapping. Must not be empty. * @param suffix The string to be used as the suffix for wrapping. Must not be empty. * @return The input string wrapped with the prefix and suffix at both ends. * @throws IllegalArgumentException If the prefix or suffix is empty. */ public static String wrap(final String str, final String prefix, final String suffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefix, cs.prefix); N.checkArgNotEmpty(prefix, cs.suffix); if (isEmpty(str)) { return concat(prefix, suffix); } else { return concat(prefix, str, suffix); } } /** * Unwraps the input string if it is wrapped by the specified prefixSuffix at both ends. * If the input string is {@code null} or empty, the original string is returned. * If the input string is not wrapped by the prefixSuffix, the original string is returned. * If the input string is wrapped by the prefixSuffix, the prefixSuffix is removed from both ends. * * @param str The string to be unwrapped. May be {@code null} or empty. * @param prefixSuffix The string used as both the prefix and suffix for unwrapping. Must not be empty. * @return The input string with the prefixSuffix removed from both ends if they were present; otherwise, the original string. * @throws IllegalArgumentException If the prefixSuffix is empty. */ public static String unwrap(final String str, final String prefixSuffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefixSuffix, cs.prefixSuffix); return unwrap(str, prefixSuffix, prefixSuffix); } /** * Unwraps the input string if it is wrapped by the specified prefix and suffix. * If the input string is {@code null} or empty, the original string is returned. * If the input string is not wrapped by the prefix and suffix, the original string is returned. * If the input string is wrapped by the prefix and suffix, the prefix and suffix are removed from both ends. * *
         * Strings.unwrap(null, "[", "]") -> ""
         * Strings.unwrap("", "[", "]") -> ""
         * Strings.unwrap("[", "[", "]") -> "["
         * Strings.unwrap("]", "[", "]") -> "["
         * Strings.unwrap("[abc]", "[", "]") -> "abc"
         * Strings.unwrap("aaaaa", "aa", "aa") -> "a"
         * Strings.unwrap("aa", "aa", "aa") -> "aa"
         * Strings.unwrap("aaa", "aa", "aa") -> "aaa"
         * Strings.unwrap("aaaa", "aa", "aa") -> ""
         * 
    * * @param str The string to be unwrapped. May be {@code null} or empty. * @param prefix The string used as the prefix for unwrapping. Must not be empty. * @param suffix The string used as the suffix for unwrapping. Must not be empty. * @return The input string with the prefix and suffix removed from both ends if they were present; otherwise, the original string. * @throws IllegalArgumentException If the prefix or suffix is empty. */ public static String unwrap(final String str, final String prefix, final String suffix) throws IllegalArgumentException { N.checkArgNotEmpty(prefix, cs.prefix); N.checkArgNotEmpty(prefix, cs.suffix); if (str == null || str.isEmpty()) { return str; } else if (str.length() - prefix.length() >= suffix.length() && str.startsWith(prefix) && str.endsWith(suffix)) { return str.substring(prefix.length(), str.length() - suffix.length()); } else { return str; } } /** * Checks if is lower case. * * @param ch * @return {@code true} if is lower case */ public static boolean isLowerCase(final char ch) { return Character.isLowerCase(ch); } /** * Checks if is ascii lower case. * * @param ch * @return {@code true} if is ascii lower case */ public static boolean isAsciiLowerCase(final char ch) { return (ch >= 'a') && (ch <= 'z'); } /** * Checks if is upper case. * * @param ch * @return {@code true} if is upper case */ public static boolean isUpperCase(final char ch) { return Character.isUpperCase(ch); } /** * Checks if is ascii upper case. * * @param ch * @return {@code true} if is ascii upper case */ public static boolean isAsciiUpperCase(final char ch) { return (ch >= 'A') && (ch <= 'Z'); } /** * Checks if all characters in the given CharSequence are lower case. * * @param cs the CharSequence to check, may be null * @return {@code true} if all characters are lower case or the CharSequence is empty; {@code false} otherwise */ public static boolean isAllLowerCase(final CharSequence cs) { if (isEmpty(cs)) { return true; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!Character.isLowerCase(cs.charAt(i))) { return false; } } return true; } /** * Checks if all characters in the given CharSequence are upper case. * * @param cs the CharSequence to check, may be null * @return {@code true} if all characters are upper case or the CharSequence is empty; {@code false} otherwise */ public static boolean isAllUpperCase(final CharSequence cs) { if (isEmpty(cs)) { return true; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!Character.isUpperCase(cs.charAt(i))) { return false; } } return true; } /** * Copied from Apache Commons Lang: StringUtils#isMixedCase. * * Checks if the given CharSequence is mixed case. * A CharSequence is considered mixed case if it contains both uppercase and lowercase characters. * If the CharSequence is empty or only contains a single character, it is not considered mixed case. * * @param cs The CharSequence to check. It may be {@code null}. * @return {@code true} if the CharSequence is mixed case, {@code false} otherwise. */ public static boolean isMixedCase(final CharSequence cs) { if (isEmpty(cs) || cs.length() == 1) { return false; } boolean containsUppercase = false; boolean containsLowercase = false; final int len = cs.length(); char ch = 0; for (int i = 0; i < len; i++) { ch = cs.charAt(i); if (Character.isUpperCase(ch)) { containsUppercase = true; } else if (Character.isLowerCase(ch)) { containsLowercase = true; } if (containsUppercase && containsLowercase) { return true; } } return false; } /** * Checks if is digit. * * @param ch * @return {@code true} if is digit * @see Character#isDigit(char) */ public static boolean isDigit(final char ch) { return Character.isDigit(ch); } /** * Checks if is letter. * * @param ch * @return {@code true} if is letter * @see Character#isLetter(char) */ public static boolean isLetter(final char ch) { return Character.isLetter(ch); } /** * Checks if is letter or digit. * * @param ch * @return {@code true} if is letter or digit * @see Character#isLetterOrDigit(char) */ public static boolean isLetterOrDigit(final char ch) { return Character.isLetterOrDigit(ch); } // -------------------------------------------------------------------------- /** *

    * Checks whether the character is ASCII 7 bit. *

    * *
         *   Strings.isAscii('a')  = true
         *   Strings.isAscii('A')  = true
         *   Strings.isAscii('3')  = true
         *   Strings.isAscii('-')  = true
         *   Strings.isAscii('\n') = true
         *   Strings.isAscii('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if less than 128 */ public static boolean isAscii(final char ch) { return ch < 128; } /** *

    * Checks whether the character is ASCII 7 bit printable. *

    * *
         *   Strings.isAsciiPrintable('a')  = true
         *   Strings.isAsciiPrintable('A')  = true
         *   Strings.isAsciiPrintable('3')  = true
         *   Strings.isAsciiPrintable('-')  = true
         *   Strings.isAsciiPrintable('\n') = false
         *   Strings.isAsciiPrintable('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if between 32 and 126 inclusive */ public static boolean isAsciiPrintable(final char ch) { return ch > 31 && ch < 127; } /** *

    * Checks whether the character is ASCII 7 bit control. *

    * *
         *   Strings.isAsciiControl('a')  = false
         *   Strings.isAsciiControl('A')  = false
         *   Strings.isAsciiControl('3')  = false
         *   Strings.isAsciiControl('-')  = false
         *   Strings.isAsciiControl('\n') = true
         *   Strings.isAsciiControl('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if less than 32 or equals 127 */ public static boolean isAsciiControl(final char ch) { return ch < 32 || ch == 127; } /** *

    * Checks whether the character is ASCII 7 bit alphabetic. *

    * *
         *   Strings.isAsciiAlpha('a')  = true
         *   Strings.isAsciiAlpha('A')  = true
         *   Strings.isAsciiAlpha('3')  = false
         *   Strings.isAsciiAlpha('-')  = false
         *   Strings.isAsciiAlpha('\n') = false
         *   Strings.isAsciiAlpha('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if between 65 and 90 or 97 and 122 inclusive */ public static boolean isAsciiAlpha(final char ch) { return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); } /** *

    * Checks whether the character is ASCII 7 bit alphabetic upper case. *

    * *
         *   Strings.isAsciiAlphaUpper('a')  = false
         *   Strings.isAsciiAlphaUpper('A')  = true
         *   Strings.isAsciiAlphaUpper('3')  = false
         *   Strings.isAsciiAlphaUpper('-')  = false
         *   Strings.isAsciiAlphaUpper('\n') = false
         *   Strings.isAsciiAlphaUpper('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if between 65 and 90 inclusive */ public static boolean isAsciiAlphaUpper(final char ch) { return ch >= 'A' && ch <= 'Z'; } /** *

    * Checks whether the character is ASCII 7 bit alphabetic lower case. *

    * *
         *   Strings.isAsciiAlphaLower('a')  = true
         *   Strings.isAsciiAlphaLower('A')  = false
         *   Strings.isAsciiAlphaLower('3')  = false
         *   Strings.isAsciiAlphaLower('-')  = false
         *   Strings.isAsciiAlphaLower('\n') = false
         *   Strings.isAsciiAlphaLower('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if between 97 and 122 inclusive */ public static boolean isAsciiAlphaLower(final char ch) { return ch >= 'a' && ch <= 'z'; } /** *

    * Checks whether the character is ASCII 7 bit numeric. *

    * *
         *   Strings.isAsciiNumeric('a')  = false
         *   Strings.isAsciiNumeric('A')  = false
         *   Strings.isAsciiNumeric('3')  = true
         *   Strings.isAsciiNumeric('-')  = false
         *   Strings.isAsciiNumeric('\n') = false
         *   Strings.isAsciiNumeric('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if between 48 and 57 inclusive */ public static boolean isAsciiNumeric(final char ch) { return ch >= '0' && ch <= '9'; } /** *

    * Checks whether the character is ASCII 7 bit numeric. *

    * *
         *   Strings.isAsciiAlphanumeric('a')  = true
         *   Strings.isAsciiAlphanumeric('A')  = true
         *   Strings.isAsciiAlphanumeric('3')  = true
         *   Strings.isAsciiAlphanumeric('-')  = false
         *   Strings.isAsciiAlphanumeric('\n') = false
         *   Strings.isAsciiAlphanumeric('©') = false
         * 
    * * @param ch * the character to check * @return {@code true} if between 48 and 57 or 65 and 90 or 97 and 122 inclusive */ public static boolean isAsciiAlphanumeric(final char ch) { return isAsciiAlpha(ch) || isAsciiNumeric(ch); } /** * Checks if the CharSequence contains only ASCII printable characters. * *

    {@code null} will return {@code false}. * An empty CharSequence (length()=0) will return {@code true}.

    * *
         * Strings.isAsciiPrintable(null)     = false
         * Strings.isAsciiPrintable("")       = true
         * Strings.isAsciiPrintable(" ")      = true
         * Strings.isAsciiPrintable("Ceki")   = true
         * Strings.isAsciiPrintable("ab2c")   = true
         * Strings.isAsciiPrintable("!ab-c~") = true
         * Strings.isAsciiPrintable("\u0020") = true
         * Strings.isAsciiPrintable("\u0021") = true
         * Strings.isAsciiPrintable("\u007e") = true
         * Strings.isAsciiPrintable("\u007f") = false
         * Strings.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
         * 
    * * @param cs * @return {@code true} if is ascii printable. {@code false} is returned if the specified {@code CharSequence} is {@code null}. */ public static boolean isAsciiPrintable(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!isAsciiPrintable(cs.charAt(i))) { return false; } } return true; } /** * Checks if is ascii alpha. * * @param cs * @return {@code true} if is ascii alpha, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null} or empty. */ public static boolean isAsciiAlpha(final CharSequence cs) { if (isEmpty(cs)) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!isAsciiAlpha(cs.charAt(i))) { return false; } } return true; } /** * Checks if is ascii alpha space. * * @param cs * @return {@code true} if is ascii alpha space, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null}. */ public static boolean isAsciiAlphaSpace(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); char ch = 0; for (int i = 0; i < len; i++) { ch = cs.charAt(i); if (!isAsciiAlpha(ch) && ch != ' ') { return false; } } return true; } /** * Checks if is ascii alphanumeric. * * @param cs * @return {@code true} if is ascii alphanumeric, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null} or empty. */ public static boolean isAsciiAlphanumeric(final CharSequence cs) { if (isEmpty(cs)) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!isAsciiAlphanumeric(cs.charAt(i))) { return false; } } return true; } /** * Checks if is ascii alphanumeric space. * * @param cs * @return {@code true} if is ascii alphanumeric space, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null}. */ public static boolean isAsciiAlphanumericSpace(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); char ch = 0; for (int i = 0; i < len; i++) { ch = cs.charAt(i); if (!isAsciiAlphanumeric(ch) && ch != ' ') { return false; } } return true; } /** * Checks if is ascii numeric. * * @param cs * @return {@code true} if is ascii numeric, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null} or empty. */ public static boolean isAsciiNumeric(final CharSequence cs) { if (isEmpty(cs)) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!isAsciiNumeric(cs.charAt(i))) { return false; } } return true; } // Character Tests // ----------------------------------------------------------------------- /** *

    * Checks if the CharSequence contains only Unicode letters. *

    * *

    * {@code null} or empty CharSequence (length()=0) will return {@code false} * . *

    * *
         * Strings.isAlpha(null)   = false
         * Strings.isAlpha("")     = false
         * Strings.isAlpha("  ")   = false
         * Strings.isAlpha("abc")  = true
         * Strings.isAlpha("ab2c") = false
         * Strings.isAlpha("ab-c") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains letters, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null} or empty. * isAlpha(CharSequence) */ public static boolean isAlpha(final CharSequence cs) { if (isEmpty(cs)) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!Character.isLetter(cs.charAt(i))) { return false; } } return true; } /** *

    * Checks if the CharSequence contains only Unicode letters and space (' '). *

    * *

    * {@code null} or empty CharSequence (length()=0) will return {@code false} * . *

    * *
         * Strings.isAlphaSpace(null)   = false
         * Strings.isAlphaSpace("")     = true
         * Strings.isAlphaSpace("  ")   = true
         * Strings.isAlphaSpace("abc")  = true
         * Strings.isAlphaSpace("ab c") = true
         * Strings.isAlphaSpace("ab2c") = false
         * Strings.isAlphaSpace("ab-c") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains letters and space, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null}. * isAlphaSpace(CharSequence) */ public static boolean isAlphaSpace(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); char ch = 0; for (int i = 0; i < len; i++) { ch = cs.charAt(i); if (!Character.isLetter(ch) && ch != ' ') { return false; } } return true; } /** *

    * Checks if the CharSequence contains only Unicode letters or digits. *

    * *

    * {@code null} or empty CharSequence (length()=0) will return {@code false} * . *

    * *
         * Strings.isAlphanumeric(null)   = false
         * Strings.isAlphanumeric("")     = false
         * Strings.isAlphanumeric("  ")   = false
         * Strings.isAlphanumeric("abc")  = true
         * Strings.isAlphanumeric("ab c") = false
         * Strings.isAlphanumeric("ab2c") = true
         * Strings.isAlphanumeric("ab-c") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains letters or digits, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null} or empty. * isAlphanumeric(CharSequence) */ public static boolean isAlphanumeric(final CharSequence cs) { if (isEmpty(cs)) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!Character.isLetterOrDigit(cs.charAt(i))) { return false; } } return true; } /** *

    * Checks if the CharSequence contains only Unicode letters, digits or space * ({@code ' '}). *

    * *

    * {@code null} or empty CharSequence (length()=0) will return {@code false} * . *

    * *
         * Strings.isAlphanumericSpace(null)   = false
         * Strings.isAlphanumericSpace("")     = true
         * Strings.isAlphanumericSpace("  ")   = true
         * Strings.isAlphanumericSpace("abc")  = true
         * Strings.isAlphanumericSpace("ab c") = true
         * Strings.isAlphanumericSpace("ab2c") = true
         * Strings.isAlphanumericSpace("ab-c") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains letters, digits or space, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null}. * isAlphanumericSpace(CharSequence) */ public static boolean isAlphanumericSpace(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); char ch = 0; for (int i = 0; i < len; i++) { ch = cs.charAt(i); if (!Character.isLetterOrDigit(ch) && ch != ' ') { return false; } } return true; } /** *

    * Checks if the CharSequence contains only Unicode digits. A decimal point * is not a Unicode digit and returns {@code false}. *

    * *

    * {@code null} will return {@code false}. An empty CharSequence * (length()=0) will return {@code false}. *

    * *

    * Note that the method does not allow for a leading sign, either positive * or negative. Also, if a String passes the numeric test, it may still * generate a NumberFormatException when parsed by Integer.parseInt or * Long.parseLong, e.g. if the value is outside the range for int or long * respectively. *

    * *
         * Strings.isNumeric(null)   = false
         * Strings.isNumeric("")     = false
         * Strings.isNumeric("  ")   = false
         * Strings.isNumeric("123")  = true
         * Strings.isNumeric("12 3") = false
         * Strings.isNumeric("ab2c") = false
         * Strings.isNumeric("12-3") = false
         * Strings.isNumeric("12.3") = false
         * Strings.isNumeric("-123") = false
         * Strings.isNumeric("+123") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains digits, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null} or empty. * isNumeric(CharSequence) */ public static boolean isNumeric(final CharSequence cs) { if (isEmpty(cs)) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!Character.isDigit(cs.charAt(i))) { return false; } } return true; } /** * Checks if the CharSequence contains only Unicode digits or space * ({@code ' '}). * A decimal point is not a Unicode digit and returns {@code false}. * *

    {@code null} will return {@code false}. * An empty CharSequence (length()=0) will return {@code true}.

    * *
         * Strings.isNumericSpace(null)   = false
         * Strings.isNumericSpace("")     = true
         * Strings.isNumericSpace("  ")   = true
         * Strings.isNumericSpace("123")  = true
         * Strings.isNumericSpace("12 3") = true
         * Strings.isNumericSpace("\u0967\u0968\u0969")  = true
         * Strings.isNumericSpace("\u0967\u0968 \u0969")  = true
         * Strings.isNumericSpace("ab2c") = false
         * Strings.isNumericSpace("12-3") = false
         * Strings.isNumericSpace("12.3") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains digits or space, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null}. * isNumericSpace(CharSequence) */ public static boolean isNumericSpace(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); char ch = 0; for (int i = 0; i < len; i++) { ch = cs.charAt(i); if (!Character.isDigit(ch) && ch != ' ') { return false; } } return true; } /** * Checks if the CharSequence contains only whitespace. * *

    Whitespace is defined by {@link Character#isWhitespace(char)}.

    * *

    {@code null} will return {@code false}. * An empty CharSequence (length()=0) will return {@code true}.

    * *
         * Strings.isWhitespace(null)   = false
         * Strings.isWhitespace("")     = true
         * Strings.isWhitespace("  ")   = true
         * Strings.isWhitespace("abc")  = false
         * Strings.isWhitespace("ab2c") = false
         * Strings.isWhitespace("ab-c") = false
         * 
    * * @param cs * the CharSequence to check, may be null * @return {@code true} if only contains whitespace, and is {@code non-null}. {@code false} is returned if the specified {@code CharSequence} is {@code null}. * isWhitespace(CharSequence) */ public static boolean isWhitespace(final CharSequence cs) { if (cs == null) { return false; } final int len = cs.length(); for (int i = 0; i < len; i++) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } /** * Note: It's copied from NumberUtils in Apache Commons Lang under Apache * License 2.0 * *

    * Checks whether the String a valid Java number. {@code true} is * returned if there is a number which can be initialized by * {@code createNumber} with specified String. *

    * *

    * {@code Null} and empty String will return {@code false}. *

    * * @param str the {@code String} to check * @return {@code true} if the string is a correctly formatted number * @see Numbers#isNumber(String) * @see Numbers#isCreatable(String) * @see Numbers#isParsable(String) * validation * @deprecated use {@link Numbers#isNumber(String)} instead */ @Deprecated public static boolean isNumber(final String str) { return Numbers.isNumber(str); } /** * {@code true} is returned if the specified {@code str} only * includes characters ('0' ~ '9', '.', '-', '+', 'e'). * {@code false} is return if the specified String is null/empty, or contains empty chars. * * "0" => true * " 0.1 " => false * "abc" => false * "1 a" => false * "2e10" => true * "2E-10" => true * * @param str * @return {@code true} if is ascii digital number */ public static boolean isAsciiDigitalNumber(final String str) { if (str == null || str.isEmpty()) { return false; } int count = 0; final int len = str.length(); char ch = str.charAt(0); int i = 0; if (ch == '+' || ch == '-') { i++; } for (; i < len; i++) { ch = str.charAt(i); if (ch >= '0' && ch <= '9') { count++; } else { break; } } if (i < len && str.charAt(i) == '.') { if (count == 0) { return false; } else { count = 0; } i++; } for (; i < len; i++) { ch = str.charAt(i); if (ch >= '0' && ch <= '9') { count++; } else { break; } } if (count == 0) { return false; } if (i == len) { return true; } ch = str.charAt(i); if (ch != 'e' && ch != 'E') { return false; } else { i++; } count = 0; if (i < len && (str.charAt(i) == '+' || str.charAt(i) == '-')) { i++; } for (; i < len; i++) { ch = str.charAt(i); if (ch >= '0' && ch <= '9') { count++; } else { break; } } //NOSONAR return (count != 0) && (i == len); } /** * {@code true} is returned if the specified {@code str} only * includes characters ('0' ~ '9', '-', '+' ). * {@code false} is return if the specified String is null/empty, or contains empty chars. * * "-123" => true * "+123" => true * "123" => true * "+0" => true * "-0" => true * "0" => true * " 0.1 " => false * "abc" => false * "1 a" => false * "2e10" => false * * @param str * @return {@code true} if is ascii digital integer */ public static boolean isAsciiDigitalInteger(final String str) { if (str == null || str.isEmpty()) { return false; } int count = 0; final int len = str.length(); char ch = str.charAt(0); int i = 0; if (ch == '+' || ch == '-') { i++; } for (; i < len; i++) { ch = str.charAt(i); if (ch >= '0' && ch <= '9') { count++; } else { break; } } if (count == 0) { return false; } return i == len; } /** * Returns the index within this string of the first occurrence of the specified character. * If a character with value {@code charValueToFind} occurs in the character sequence represented by * this {@code String} object, then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param charValueToFind The Unicode code of the character to be found. * @return The index of the first occurrence of the character in the character sequence represented by this object, * or -1 if the character does not occur. */ public static int indexOf(final String str, final int charValueToFind) { if (str == null || str.isEmpty()) { return N.INDEX_NOT_FOUND; } return str.indexOf(charValueToFind); } /** * Returns the index within the input string of the first occurrence of the specified character, starting the search at the specified index. * If a character with value {@code charValueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param charValueToFind The Unicode code of the character to be found. * @param fromIndex The index to start the search from. * @return The index of the first occurrence of the character in the character sequence represented by this object, * or -1 if the character does not occur. */ public static int indexOf(final String str, final int charValueToFind, final int fromIndex) { if (str == null || str.isEmpty()) { return N.INDEX_NOT_FOUND; } return str.indexOf(charValueToFind, fromIndex); } /** * Returns the index within the input string of the first occurrence of the specified substring. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @return The index of the first occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int indexOf(final String str, final String valueToFind) { if (str == null || valueToFind == null || valueToFind.length() > str.length()) { return N.INDEX_NOT_FOUND; } return str.indexOf(valueToFind); } /** * Returns the index within the input string of the first occurrence of the specified substring, starting the search at the specified index. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param fromIndex The index to start the search from. * @return The index of the first occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int indexOf(final String str, final String valueToFind, final int fromIndex) { if (str == null || valueToFind == null || valueToFind.length() > str.length() - fromIndex) { return N.INDEX_NOT_FOUND; } return str.indexOf(valueToFind, fromIndex); } /** * Returns the index within the input string of the first occurrence of any specified character. * If a character within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valuesToFind The array of characters to be found. * @return The index of the first occurrence of any character in the character sequence represented by this object, * or -1 if none of the characters occur. */ @SafeVarargs public static int indexOfAny(final String str, final char... valuesToFind) { return indexOfAny(str, 0, valuesToFind); } /** * Returns the index within the input string of the first occurrence of any specified character, starting the search at the specified index. * If a character within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param fromIndex The index to start the search from. * @param valuesToFind The array of characters to be found. * @return The index of the first occurrence of any character in the character sequence represented by this object, * or -1 if none of the characters occur. */ @SafeVarargs public static int indexOfAny(final String str, final int fromIndex, final char... valuesToFind) { checkInputChars(valuesToFind, cs.valuesToFind, true); if (isEmpty(str) || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } final int strLen = str.length(); char ch = 0; for (int i = Math.max(fromIndex, 0); i < strLen; i++) { ch = str.charAt(i); for (final char c : valuesToFind) { if (c == ch) { // checked by checkInputChars // if (i < strLast && j < chsLast && Character.isHighSurrogate(ch)) { // // ch is a supplementary character // if (valuesToFind[j + 1] == str.charAt(i + 1)) { // return i; // } // } else { // return i; // } return i; } } } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the first occurrence of any specified substring. * If a substring within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valuesToFind The array of substrings to be found. * @return The index of the first occurrence of any substring in the character sequence represented by this object, * or -1 if none of the substrings occur. */ @SafeVarargs public static int indexOfAny(final String str, final String... valuesToFind) { return indexOfAny(str, 0, valuesToFind); } /** * Returns the index within the input string of the first occurrence of any specified substring, starting the search at the specified index. * If a substring within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param fromIndex The index to start the search from. * @param valuesToFind The array of substrings to be found. * @return The index of the first occurrence of any substring in the character sequence represented by this object, * or -1 if none of the substrings occur. */ @SafeVarargs public static int indexOfAny(final String str, final int fromIndex, final String... valuesToFind) { if (str == null || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } int idx = 0; for (final String element : valuesToFind) { if (isEmpty(element)) { continue; } idx = indexOf(str, element, fromIndex); if (idx != N.INDEX_NOT_FOUND) { return idx; } } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the first occurrence of any character * that is not in the specified array of characters to exclude. * If a character not within the array {@code valuesToExclude} occurs in the character * sequence represented by the input {@code String} object, then the index of the first * such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valuesToExclude The array of characters to exclude from the search. * @return The index of the first occurrence of any character not in the array of characters * to exclude, or -1 if all characters are in the array or the string is {@code null} or empty. */ @SafeVarargs public static int indexOfAnyBut(final String str, final char... valuesToExclude) { return indexOfAnyBut(str, 0, valuesToExclude); } /** * Returns the index within the input string of the first occurrence of any character * that is not in the specified array of characters to exclude, starting the search at the specified index. * If a character not within the array {@code valuesToExclude} occurs in the character * sequence represented by the input {@code String} object, then the index of the first * such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param fromIndex The index to start the search from. * @param valuesToExclude The array of characters to exclude from the search. * @return The index of the first occurrence of any character not in the array of characters * to exclude, or -1 if all characters are in the array or the string is {@code null} or empty. */ @SafeVarargs public static int indexOfAnyBut(final String str, final int fromIndex, final char... valuesToExclude) { checkInputChars(valuesToExclude, cs.valuesToExclude, true); if (str == null || str.isEmpty()) { return N.INDEX_NOT_FOUND; } if (N.isEmpty(valuesToExclude)) { return 0; } final int strLen = str.length(); char ch = 0; outer: for (int i = Math.max(fromIndex, 0); i < strLen; i++) {//NOSONAR ch = str.charAt(i); for (final char c : valuesToExclude) { if (c == ch) { // checked by checkInputChars // if (i < strLast && j < chsLast && Character.isHighSurrogate(ch)) { // if (valuesToExclude[j + 1] == str.charAt(i + 1)) { // continue outer; // } // } else { // continue outer; // } continue outer; } } return i; } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the first occurrence of the specified substring, * using the specified delimiter to separate the search. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param delimiter The delimiter to separate the search. * @return The index of the first occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int indexOf(final String str, final String valueToFind, final String delimiter) { return indexOf(str, valueToFind, delimiter, 0); } /** * Returns the index within the input string of the first occurrence of the specified substring, * using the specified delimiter to separate the search, starting the search at the specified index. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param delimiter The delimiter to separate the search. * @param fromIndex The index to start the search from. * @return The index of the first occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int indexOf(final String str, final String valueToFind, final String delimiter, final int fromIndex) { if (isEmpty(delimiter)) { return indexOf(str, valueToFind, fromIndex); } if (str == null || valueToFind == null) { return N.INDEX_NOT_FOUND; } final int len = str.length(); final int targetLen = fromIndex > 0 ? len - fromIndex : len; final int substrLen = valueToFind.length(); final int delimiterLen = delimiter.length(); if (targetLen < substrLen || (targetLen > substrLen && targetLen - substrLen < delimiterLen)) { return N.INDEX_NOT_FOUND; } final int index = str.indexOf(valueToFind, fromIndex); if (index < 0) { return N.INDEX_NOT_FOUND; } if ((index == fromIndex || (index - fromIndex >= delimiterLen && delimiter.equals(str.substring(index - delimiterLen, index)))) && (index + substrLen == len || (len >= index + substrLen + delimiterLen && delimiter.equals(str.substring(index + substrLen, index + substrLen + delimiterLen))))) { return index; } int idx = str.indexOf(delimiter + valueToFind + delimiter, index); if (idx >= 0) { return idx + delimiterLen; } else { idx = str.indexOf(delimiter + valueToFind, index); if (idx >= 0 && idx + delimiterLen + substrLen == len) { return idx + delimiterLen; } } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the first occurrence of the specified substring, ignoring case considerations. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @return The index of the first occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int indexOfIgnoreCase(final String str, final String valueToFind) { return indexOfIgnoreCase(str, valueToFind, 0); } /** * Returns the index within the input string of the first occurrence of the specified substring, ignoring case considerations, * starting the search at the specified index. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param fromIndex The index to start the search from. * @return The index of the first occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int indexOfIgnoreCase(final String str, final String valueToFind, final int fromIndex) { if (str == null || valueToFind == null || valueToFind.length() > str.length() - fromIndex) { return N.INDEX_NOT_FOUND; } for (int i = fromIndex, len = str.length(), substrLen = valueToFind.length(), end = len - substrLen + 1; i < end; i++) { if (str.regionMatches(true, i, valueToFind, 0, substrLen)) { return i; } } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the first occurrence of the specified substring, ignoring case considerations. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param delimiter The delimiter to be used for the search. * @return The index of the first occurrence of the substring in the character sequence represented by this object, or -1 if the substring does not occur. */ public static int indexOfIgnoreCase(final String str, final String valueToFind, final String delimiter) { return indexOfIgnoreCase(str, valueToFind, delimiter, 0); } /** * Returns the index within the input string of the first occurrence of the specified substring, ignoring case considerations. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the first such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param delimiter The delimiter to be used for the search. * @param fromIndex The index to start the search from. * @return The index of the first occurrence of the substring in the character sequence represented by this object, or -1 if the substring does not occur. */ public static int indexOfIgnoreCase(final String str, final String valueToFind, final String delimiter, final int fromIndex) { if (isEmpty(delimiter)) { return indexOfIgnoreCase(str, valueToFind, fromIndex); } if (str == null || valueToFind == null) { return N.INDEX_NOT_FOUND; } final int len = str.length(); final int targetLen = fromIndex > 0 ? len - fromIndex : len; final int substrLen = valueToFind.length(); final int delimiterLen = delimiter.length(); if (targetLen < substrLen || (targetLen > substrLen && targetLen - substrLen < delimiterLen)) { return N.INDEX_NOT_FOUND; } final int index = indexOfIgnoreCase(str, valueToFind, fromIndex); if (index < 0) { return N.INDEX_NOT_FOUND; } if ((index == fromIndex || (index - fromIndex >= delimiterLen && delimiter.equalsIgnoreCase(str.substring(index - delimiterLen, index)))) && (index + substrLen == len || (len >= index + substrLen + delimiterLen && delimiter.equalsIgnoreCase(str.substring(index + substrLen, index + substrLen + delimiterLen))))) { return index; } int idx = indexOfIgnoreCase(str, delimiter + valueToFind + delimiter, index); if (idx >= 0) { return idx + delimiterLen; } else { idx = indexOfIgnoreCase(str, delimiter + valueToFind, index); if (idx >= 0 && idx + delimiterLen + substrLen == len) { return idx + delimiterLen; } } return N.INDEX_NOT_FOUND; } /** * Returns the index within this string of the last occurrence of the specified character. * If a character with value {@code charValueToFind} occurs in the character sequence represented by * this {@code String} object, then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param charValueToFind The Unicode code of the character to be found. * @return The index of the last occurrence of the character in the character sequence represented by this object, or -1 if the character does not occur. */ public static int lastIndexOf(final String str, final int charValueToFind) { if (str == null || str.isEmpty()) { return N.INDEX_NOT_FOUND; } return str.lastIndexOf(charValueToFind); } /** * Returns the index within this string of the last occurrence of the * specified character, searching backward starting at the specified index. * For values of {@code ch} in the range from 0 to 0xFFFF (inclusive), * the index returned is the largest value k such that:
    * *
         * {@code (this.charAt(k) == ch) && (k <= fromIndex)}
         * 
    * *
    is {@code true}. For other values of {@code ch}, it is the * largest value k such that:
    * *
         * {@code (this.codePointAt(k) == ch) && (k <= fromIndex)}
         * 
    * *
    is {@code true}. In either case, if no such character occurs in * this string at or before position {@code fromIndex}, then * {@code -1} is returned. * *

    * All indices are specified in {@code char} values (Unicode code * units). * * @param str * @param charValueToFind a character (Unicode code point). * @param startIndexFromBack the index to start the search from. There is no restriction on * the value of {@code fromIndex}. If it is greater than or * equal to the length of this string, it has the same effect as * if it were equal to one less than the length of this string: * this entire string may be searched. If it is negative, it has * the same effect as if it were -1: -1 is returned. * @return * character sequence represented by this object that is less than * or equal to {@code fromIndex}, or {@code -1} if the * character does not occur before that point. */ public static int lastIndexOf(final String str, final int charValueToFind, final int startIndexFromBack) { if (str == null || str.isEmpty() || startIndexFromBack < 0) { return N.INDEX_NOT_FOUND; } return str.lastIndexOf(charValueToFind, startIndexFromBack); } /** * Last index of. * * @param str * @param valueToFind * @return */ public static int lastIndexOf(final String str, final String valueToFind) { if (str == null || valueToFind == null || valueToFind.length() > str.length()) { return N.INDEX_NOT_FOUND; } return str.lastIndexOf(valueToFind); } /** * Returns the index within {@code str} of the last occurrence of the * specified {@code substr}, searching backward starting at the * specified index. * *

    * The returned index is the largest value k for which:

    * *
         * {@code k <= fromIndex && str.startsWith(substr, k)}
         * 
    * *
    If no such value of k exists, then {@code -1} is * returned. * * @param str * @param valueToFind * @param startIndexFromBack The index to start the search from, searching backward. * @return */ public static int lastIndexOf(final String str, final String valueToFind, final int startIndexFromBack) { if (str == null || valueToFind == null || startIndexFromBack < 0 || valueToFind.length() > str.length()) { return N.INDEX_NOT_FOUND; } return str.lastIndexOf(valueToFind, startIndexFromBack); } /** * Returns the index within the input string of the last occurrence of the specified substring, * using the specified delimiter to separate the search. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param delimiter The delimiter to separate the search. * @return The index of the last occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int lastIndexOf(final String str, final String valueToFind, final String delimiter) { return lastIndexOf(str, valueToFind, delimiter, str.length()); } /** * Returns the index within the input string of the last occurrence of the specified substring, * using the specified delimiter to separate the search, starting the search at the specified index. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param delimiter The delimiter to separate the search. * @param startIndexFromBack The index to start the search from, searching backward. * @return The index of the last occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int lastIndexOf(final String str, final String valueToFind, final String delimiter, final int startIndexFromBack) { if (isEmpty(delimiter)) { return lastIndexOf(str, valueToFind, startIndexFromBack); } else if (str == null || valueToFind == null || startIndexFromBack < 0) { return N.INDEX_NOT_FOUND; } final int len = str.length(); final int substrLen = valueToFind.length(); final int delimiterLen = delimiter.length(); if (len < substrLen || (len > substrLen && len - substrLen < delimiterLen)) { return N.INDEX_NOT_FOUND; } int index = str.lastIndexOf(delimiter + valueToFind, startIndexFromBack); if (index >= 0 && index + delimiter.length() + valueToFind.length() == len) { return index + delimiter.length(); } index = str.lastIndexOf(delimiter + valueToFind + delimiter, startIndexFromBack); if (index >= 0) { return index + delimiter.length(); } index = str.lastIndexOf(valueToFind, startIndexFromBack); if (index < 0) { return N.INDEX_NOT_FOUND; } //noinspection DuplicateExpressions if (index == 0 && (index + valueToFind.length() == len || (len >= index + valueToFind.length() + delimiter.length() && delimiter.equals(str.substring(index + valueToFind.length(), index + valueToFind.length() + delimiter.length()))))) { return index; } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the last occurrence of the specified substring, ignoring case considerations. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @return The index of the last occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int lastIndexOfIgnoreCase(final String str, final String valueToFind) { if (str == null || valueToFind == null || valueToFind.length() > str.length()) { return N.INDEX_NOT_FOUND; } return lastIndexOfIgnoreCase(str, valueToFind, str.length()); } /** * Returns the index within the input string of the last occurrence of the specified substring, ignoring case considerations, * searching backward starting at the specified index. * If a substring with value {@code valueToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The substring to be found. * @param startIndexFromBack The index to start the search from, searching backward. * @return The index of the last occurrence of the substring in the character sequence represented by this object, * or -1 if the substring does not occur. */ public static int lastIndexOfIgnoreCase(final String str, final String valueToFind, final int startIndexFromBack) { if (str == null || valueToFind == null || startIndexFromBack < 0 || valueToFind.length() > str.length()) { return N.INDEX_NOT_FOUND; } for (int i = N.min(startIndexFromBack, str.length() - valueToFind.length()), substrLen = valueToFind.length(); i >= 0; i--) { if (str.regionMatches(true, i, valueToFind, 0, substrLen)) { return i; } } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the last occurrence of any specified character. * If a character within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valuesToFind The array of characters to be found. * @return The index of the last occurrence of any character in the character sequence represented by this object, * or -1 if none of the characters occur. */ @SafeVarargs public static int lastIndexOfAny(final String str, final char... valuesToFind) { checkInputChars(valuesToFind, cs.valuesToFind, true); if (isEmpty(str) || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } int idx = 0; for (final char ch : valuesToFind) { idx = str.lastIndexOf(ch); if (idx != N.INDEX_NOT_FOUND) { return idx; } } final int strLen = str.length(); final int chsLen = valuesToFind.length; char ch = 0; for (int i = strLen - 1; i >= 0; i--) { ch = str.charAt(i); for (int j = chsLen - 1; j >= 0; j--) { if (valuesToFind[j] == ch) { // checked by checkInputChars // if (i > 0 && j > 0 && Character.isHighSurrogate(ch = str.charAt(i - 1))) { // // ch is a supplementary character // if (valuesToFind[j - 1] == ch) { // return i - 1; // } // } else { // return i; // } return i; } } } return N.INDEX_NOT_FOUND; } /** * Returns the index within the input string of the last occurrence of any specified substring. * If a substring within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the index of the last such occurrence is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valuesToFind The array of substrings to be found. * @return The index of the last occurrence of any substring in the character sequence represented by this object, * or -1 if none of the substrings occur. */ @SafeVarargs public static int lastIndexOfAny(final String str, final String... valuesToFind) { if (str == null || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } int idx = 0; for (final String substr : valuesToFind) { if (substr == null) { continue; } idx = str.lastIndexOf(substr); if (idx != N.INDEX_NOT_FOUND) { return idx; } } return N.INDEX_NOT_FOUND; } // Shared code between ordinalIndexOf(String,String,int) and /** * Ordinal index of. * * @param str * @param substr * @param ordinal * @param isLastIndex * @return */ // lastOrdinalIndexOf(String,String,int) private static int ordinalIndexOf(final String str, final String substr, final int ordinal, final boolean isLastIndex) { if (ordinal < 1) { throw new IllegalArgumentException("ordinal(" + ordinal + ") must be >= 1"); } if (str == null || substr == null || substr.length() > str.length()) { return N.INDEX_NOT_FOUND; } int fromIndex = isLastIndex ? str.length() : 0; for (int found = 0; fromIndex >= 0;) { fromIndex = isLastIndex ? str.lastIndexOf(substr, fromIndex) : str.indexOf(substr, fromIndex); if (fromIndex < 0) { return N.INDEX_NOT_FOUND; } if (++found >= ordinal) { break; } fromIndex = isLastIndex ? (fromIndex - substr.length()) : (fromIndex + substr.length()); } return fromIndex; } /** * Returns the smallest index of any specified substring within the input string. * If a substring within the array {@code valuesToFind} occurs in the character sequence represented by the input {@code String} object, * then the smallest index of such occurrences is returned. * * @param str The string to be checked. May be {@code null} or empty. * @param valuesToFind The array of substrings to be found. * @return The smallest index of any substring in the character sequence represented by this object, * or -1 if none of the substrings occur. */ @SafeVarargs public static int smallestIndicesOfAll(final String str, final String... valuesToFind) { return smallestIndicesOfAll(str, 0, valuesToFind); } /** *

    Find the smallest index of any substrings in {@code valuesToFind} from {@code fromIndex}.

    * * * @param str * @param fromIndex * @param valuesToFind * @return * @see #indexOfAny(String, int, String[]) */ @SafeVarargs public static int smallestIndicesOfAll(final String str, final int fromIndex, final String... valuesToFind) { if (str == null || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } final int len = str.length(); int result = N.INDEX_NOT_FOUND; for (final String substr : valuesToFind) { if (substr == null || (fromIndex + substr.length() > len)) { continue; } final int tmp = str.indexOf(substr, fromIndex); result = tmp >= 0 && (result == N.INDEX_NOT_FOUND || tmp < result) ? tmp : result; if (result == fromIndex) { break; } } return result; } /** *

    Find the largest index of any substrings in {@code valuesToFind}.

    * * @param str * @param valuesToFind * @return * @see #indexOfAny(String, String...) */ @SafeVarargs public static int largestIndicesOfAll(final String str, final String... valuesToFind) { return largestIndicesOfAll(str, 0, valuesToFind); } /** *

    Find the largest index of any substrings in {@code valuesToFind}.

    * * * @param str * @param fromIndex * @param valuesToFind * @return * @see #indexOfAny(String, int, String[]) */ public static int largestIndicesOfAll(final String str, final int fromIndex, final String... valuesToFind) { if (str == null || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } final int len = str.length(); @SuppressWarnings("resource") final List sortedSubstrs = Stream.of(valuesToFind) // .filter(it -> !(it == null || (fromIndex + it.length() > len))) .sortedByInt(N::len) .toList(); int result = N.INDEX_NOT_FOUND; for (final String substr : sortedSubstrs) { result = N.max(result, str.indexOf(substr, fromIndex)); if (result == len - substr.length()) { break; } } return result; } /** *

    Find the smallest last index of any substrings in {@code valuesToFind}.

    * This method starts searching from the end of the string towards the beginning. * * @param str The string to search within. It may be {@code null}. * @param valuesToFind The substrings to find within the string. These may be empty or {@code null}. * @return The smallest last index where any of the provided substrings is found in the string. * If none of the substrings are found, it returns -1. * @see #indexOfAny(String, String...) */ @SafeVarargs public static int smallestLastIndicesOfAll(final String str, final String... valuesToFind) { return smallestLastIndicesOfAll(str, N.len(str), valuesToFind); } /** *

    Find the smallest last index of any substrings in {@code valuesToFind} from {@code fromIndex}.

    * * * @param str * @param fromIndex * @param valuesToFind * @return * @see #indexOfAny(String, int, String[]) */ public static int smallestLastIndicesOfAll(final String str, final int fromIndex, final String... valuesToFind) { if (str == null || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } final int len = str.length(); int result = N.INDEX_NOT_FOUND; for (final String substr : valuesToFind) { if (substr == null || substr.length() > len) { continue; } final int tmp = str.lastIndexOf(substr, fromIndex); result = tmp >= 0 && (result == N.INDEX_NOT_FOUND || tmp < result) ? tmp : result; if (result == 0) { break; } } return result; } /** *

    Find the largest index among the first index of any substrings in {@code valuesToFind}.

    * * @param str * @param valuesToFind * @return * @see #indexOfAny(String, String...) */ @SafeVarargs public static int largestLastIndicesOfAll(final String str, final String... valuesToFind) { return largestLastIndicesOfAll(str, N.len(str), valuesToFind); } /** *

    Find the largest index among the first index of any substrings in {@code valuesToFind}.

    * * * @param str * @param fromIndex * @param valuesToFind * @return * @see #indexOfAny(String, int, String[]) */ @SafeVarargs public static int largestLastIndicesOfAll(final String str, final int fromIndex, final String... valuesToFind) { if (str == null || N.isEmpty(valuesToFind)) { return N.INDEX_NOT_FOUND; } final int len = str.length(); int result = N.INDEX_NOT_FOUND; for (final String substr : valuesToFind) { if (substr == null || substr.length() > len) { continue; } result = N.max(result, str.lastIndexOf(substr, fromIndex)); if (result == fromIndex) { break; } } return result; } /** * Finds the n-th occurrence of the specified value within the input string. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The value to be found. * @param ordinal The n-th occurrence to find. * @return The index of the n-th occurrence of the specified value within the input string, * or -1 if the value does not occur as many times as requested. */ public static int ordinalIndexOf(final String str, final String valueToFind, final int ordinal) { return ordinalIndexOf(str, valueToFind, ordinal, false); } /** * Finds the n-th last occurrence of the specified value within the input string. * * @param str The string to be checked. May be {@code null} or empty. * @param valueToFind The value to be found. * @param ordinal The n-th last occurrence to find. * @return The index of the n-th last occurrence of the specified value within the input string, * or -1 if the value does not occur as many times as requested. */ public static int lastOrdinalIndexOf(final String str, final String valueToFind, final int ordinal) { return ordinalIndexOf(str, valueToFind, ordinal, true); } /** * Counts the number of occurrences of the specified character in the given string. * * @param str the string to be checked, may be {@code null} or empty * @param charValueToFind the character to be counted * @return the number of occurrences of the specified character in the string, or 0 if the string is {@code null} or empty * @see N#occurrencesOf(String, char) */ @SuppressWarnings("deprecation") public static int countMatches(final String str, final char charValueToFind) { if (str == null || str.isEmpty()) { return 0; } int occurrences = 0; for (final char e : InternalUtil.getCharsForReadOnly(str)) { if (e == charValueToFind) { occurrences++; } } return occurrences; } /** * Counts the number of occurrences of the specified substring in the given string. * * @param str the string to be checked, may be {@code null} or empty * @param valueToFind the substring to be counted * @return the number of occurrences of the specified substring in the string, or 0 if the string is {@code null} or empty * @see N#occurrencesOf(String, String) */ public static int countMatches(final String str, final String valueToFind) { if (str == null || valueToFind == null) { return 0; } int occurrences = 0; for (int len = N.len(str), substrLen = N.len(valueToFind), index = 0, fromIndex = 0, toIndex = len - substrLen; fromIndex <= toIndex;) { index = str.indexOf(valueToFind, fromIndex); if (index < 0) { break; } else { fromIndex = index + substrLen; occurrences++; } } return occurrences; } /** * Checks if the specified character is present in the given string. * * @param str the string to be checked, may be {@code null} or empty * @param charValueToFind the character to be found * @return {@code true} if the character is found in the string, {@code false} otherwise */ public static boolean contains(final String str, final char charValueToFind) { if (str == null || str.isEmpty()) { return false; } return indexOf(str, charValueToFind) != N.INDEX_NOT_FOUND; } /** * Checks if the specified substring is present in the given string. * * @param str the string to be checked, may be {@code null} or empty * @param valueToFind the substring to be found * @return {@code true} if the substring is found in the string, {@code false} otherwise */ public static boolean contains(final String str, final String valueToFind) { if (str == null || valueToFind == null) { return false; } return indexOf(str, valueToFind) != N.INDEX_NOT_FOUND; } /** * Checks if the specified substring is present in the given string, considering the specified delimiter. * * @param str the string to be checked, may be {@code null} or empty * @param valueToFind the substring to be found * @param delimiter the delimiter to be considered * @return {@code true} if the substring is found in the string considering the delimiter, {@code false} otherwise */ public static boolean contains(final String str, final String valueToFind, final String delimiter) { if (str == null || valueToFind == null) { return false; } return indexOf(str, valueToFind, delimiter) != N.INDEX_NOT_FOUND; } /** * Checks if the specified substring is present in the given string, ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param valueToFind the substring to be found * @return {@code true} if the substring is found in the string, ignoring case considerations, {@code false} otherwise */ public static boolean containsIgnoreCase(final String str, final String valueToFind) { if (str == null || valueToFind == null) { return false; } return indexOfIgnoreCase(str, valueToFind) != N.INDEX_NOT_FOUND; } /** * Checks if the specified substring is present in the given string, considering the specified delimiter and ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param valueToFind the substring to be found * @param delimiter the delimiter to be considered * @return {@code true} if the substring is found in the string considering the delimiter and ignoring case considerations, {@code false} otherwise */ public static boolean containsIgnoreCase(final String str, final String valueToFind, final String delimiter) { if (str == null || valueToFind == null) { return false; } return indexOfIgnoreCase(str, valueToFind, delimiter) != N.INDEX_NOT_FOUND; } /** * Checks if all the specified characters are present in the given string. * The method returns {@code true} if the specified character array is empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of characters to be found * @return {@code true} if all the characters are found in the given string or the specified {@code valuesToFind} char array is {@code null} or empty, {@code false} otherwise. */ @SafeVarargs public static boolean containsAll(final String str, final char... valuesToFind) { checkInputChars(valuesToFind, cs.valuesToFind, true); if (N.isEmpty(valuesToFind)) { return true; } if (str == null || str.isEmpty()) { return false; } for (final char ch : valuesToFind) { if (str.indexOf(ch) < 0) { return false; } } return true; } /** * Checks if all the specified substrings are present in the given string. * The method returns {@code true} if the specified substring array is empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of substrings to be found * @return {@code true} if all the substrings are found in the given string or the specified substring array is {@code null} or empty, {@code false} otherwise */ @SafeVarargs public static boolean containsAll(final String str, final String... valuesToFind) { if (N.isEmpty(valuesToFind)) { return true; } if (str == null || str.isEmpty()) { return false; } for (final String searchStr : valuesToFind) { if (!Strings.contains(str, searchStr)) { return false; } } return true; } /** * Checks if all the specified substrings are present in the given string, ignoring case considerations. * The method returns {@code true} if the specified substring array is empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of substrings to be found * @return {@code true} if all the substrings are found in the given string or the specified substring array is {@code null} or empty, ignoring case considerations, {@code false} otherwise */ @SafeVarargs public static boolean containsAllIgnoreCase(final String str, final String... valuesToFind) { if (N.isEmpty(valuesToFind)) { return true; } if (str == null || str.isEmpty()) { return false; } for (final String searchStr : valuesToFind) { if (!Strings.containsIgnoreCase(str, searchStr)) { return false; } } return true; } /** * Checks if any of the specified characters are present in the given string. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of characters to be found * @return {@code true} if any of the characters are found in the given string, {@code false} otherwise if not or if the specified {@code valuesToFind} char array is {@code null} or empty * @see #containsNone(String, char...) */ @SafeVarargs public static boolean containsAny(final String str, final char... valuesToFind) { if (isEmpty(str) || N.isEmpty(valuesToFind)) { return false; } return indexOfAny(str, valuesToFind) != N.INDEX_NOT_FOUND; } /** * Checks if any of the specified substrings are present in the given string. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of substrings to be found * @return {@code true} if any of the substrings are found in the given string, {@code false} otherwise if not or if the specified substrings array is {@code null} or empty * @see #containsNone(String, String...) */ @SafeVarargs public static boolean containsAny(final String str, final String... valuesToFind) { if (isEmpty(str) || N.isEmpty(valuesToFind)) { return false; } return indexOfAny(str, valuesToFind) != N.INDEX_NOT_FOUND; } /** * Checks if any of the specified substrings are present in the given string, ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of substrings to be found * @return {@code true} if any of the substrings are found in the given string, ignoring case considerations, {@code false} otherwise if not or if the specified substrings array is {@code null} or empty * @see #containsNoneIgnoreCase(String, String...) */ @SafeVarargs public static boolean containsAnyIgnoreCase(final String str, final String... valuesToFind) { if (isEmpty(str) || N.isEmpty(valuesToFind)) { return false; } if (valuesToFind.length == 1) { return containsIgnoreCase(str, valuesToFind[0]); } else if (valuesToFind.length == 2) { if (containsIgnoreCase(str, valuesToFind[0])) { return true; } return containsIgnoreCase(str, valuesToFind[1]); } final String sourceText = str.toLowerCase(); for (final String searchStr : valuesToFind) { if (isNotEmpty(searchStr) && indexOf(sourceText, searchStr.toLowerCase()) != N.INDEX_NOT_FOUND) { return true; } } return false; } /** * Checks if none of the specified characters are present in the given string. * The method returns {@code true} if the string is {@code null} or empty, or if the specified character array is empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of characters to be checked * @return {@code true} if none of the characters are found in the given string or if the given string is {@code null} or empty, or if the specified {@code valuesToFind} char array is {@code null} or empty, {@code false} otherwise * @see #containsAny(String, char...) */ @SafeVarargs public static boolean containsNone(final String str, final char... valuesToFind) { checkInputChars(valuesToFind, cs.valuesToFind, true); if (isEmpty(str) || N.isEmpty(valuesToFind)) { return true; } final int strLen = str.length(); char ch = 0; for (int i = 0; i < strLen; i++) { ch = str.charAt(i); for (final char c : valuesToFind) { if (c == ch) { // checked by checkInputChars // if (Character.isHighSurrogate(ch)) { // if ((j == chsLast) || (i < strLast && valuesToFind[j + 1] == str.charAt(i + 1))) { // return false; // } // } else { // // ch is in the Basic Multilingual Plane // return false; // } return false; } } } return true; } /** * Checks if none of the specified substrings are present in the given string. * The method returns {@code true} if the string is {@code null} or empty, or if the specified substring array is empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of substrings to be checked * @return {@code true} if none of the substrings are found in the given string or if the given string is {@code null} or empty, or if the specified {@code valuesToFind} char array is {@code null} or empty, {@code false} otherwise * @see #containsAny(String, String...) */ @SafeVarargs public static boolean containsNone(final String str, final String... valuesToFind) { if (isEmpty(str) || N.isEmpty(valuesToFind)) { return true; } return !containsAny(str, valuesToFind); } /** * Checks if none of the specified substrings are present in the given string, ignoring case considerations. * The method returns {@code true} if the string is {@code null} or empty, or if the specified substring array is empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the array of substrings to be checked * @return {@code true} if none of the substrings are found in the given string or if the given string is {@code null} or empty, or if the specified {@code valuesToFind} char array is {@code null} or empty, ignoring case considerations, {@code false} otherwise * @see #containsAnyIgnoreCase(String, String...) */ @SafeVarargs public static boolean containsNoneIgnoreCase(final String str, final String... valuesToFind) { if (isEmpty(str) || N.isEmpty(valuesToFind)) { return true; } return !containsAnyIgnoreCase(str, valuesToFind); } /** * Checks if the given string contains only the specified character. * The method returns {@code true} if the string is {@code null} or empty. * * @param str the string to be checked, may be {@code null} or empty * @param valuesToFind the character to be checked * @return {@code true} if the given string contains only the specified character or the given string is {@code null} or empty, {@code false} otherwise */ @SafeVarargs public static boolean containsOnly(final String str, final char... valuesToFind) { if (isEmpty(str)) { return true; } else if (N.isEmpty(valuesToFind)) { return false; } return indexOfAnyBut(str, valuesToFind) == N.INDEX_NOT_FOUND; } /** * Checks if the given string contains any whitespace characters. * * @param str the string to be checked, may be {@code null} or empty * @return {@code true} if the string contains any whitespace characters, {@code false} otherwise */ // From org.springframework.util.StringUtils, under Apache License 2.0 public static boolean containsWhitespace(final String str) { if (str == null || str.isEmpty()) { return false; } for (int i = 0, len = str.length(); i < len; i++) { if (Character.isWhitespace(str.charAt(i))) { return true; } } return false; } /** * Checks if the given string starts with the specified prefix. * * @param str the string to be checked, may be {@code null} or empty * @param prefix the prefix to be checked * @return {@code true} if the string starts with the specified prefix, {@code false} otherwise */ public static boolean startsWith(final String str, final String prefix) { return startsWith(str, prefix, false); } /** * Checks if the given string starts with the specified prefix, ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param prefix the prefix to be checked * @return {@code true} if the string starts with the specified prefix, ignoring case considerations, {@code false} otherwise */ public static boolean startsWithIgnoreCase(final String str, final String prefix) { return startsWith(str, prefix, true); } /** * Checks if the given string starts with the specified prefix, with an option to ignore case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param prefix the prefix to be checked * @param ignoreCase if {@code true}, the comparison is case-insensitive * @return {@code true} if the string starts with the specified prefix, considering the case sensitivity option, {@code false} otherwise */ private static boolean startsWith(final String str, final String prefix, final boolean ignoreCase) { if (str == null || prefix == null || prefix.length() > str.length()) { return false; } return ignoreCase ? str.regionMatches(true, 0, prefix, 0, prefix.length()) : str.startsWith(prefix); } /** * Checks if the given string starts with any of the specified substrings. * * @param str the string to be checked, may be {@code null} or empty * @param substrs the array of substrings to be checked * @return {@code true} if the string starts with any of the specified substrings, {@code false} otherwise */ @SafeVarargs public static boolean startsWithAny(final String str, final String... substrs) { if (str == null || N.isEmpty(substrs)) { return false; } for (final String substr : substrs) { if (startsWith(str, substr)) { return true; } } return false; } /** * Checks if the given string starts with any of the specified substrings, ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param substrs the array of substrings to be checked * @return {@code true} if the string starts with any of the specified substrings, ignoring case considerations, {@code false} otherwise */ @SafeVarargs public static boolean startsWithAnyIgnoreCase(final String str, final String... substrs) { if (str == null || N.isEmpty(substrs)) { return false; } for (final String substr : substrs) { if (startsWithIgnoreCase(str, substr)) { return true; } } return false; } /** * Checks if the given string ends with the specified suffix. * * @param str the string to be checked, may be {@code null} or empty * @param suffix the suffix to be checked * @return {@code true} if the string ends with the specified suffix, {@code false} otherwise */ public static boolean endsWith(final String str, final String suffix) { return endsWith(str, suffix, false); } /** * Checks if the given string ends with the specified suffix, ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param suffix the suffix to be checked * @return {@code true} if the string ends with the specified suffix, ignoring case considerations, {@code false} otherwise */ public static boolean endsWithIgnoreCase(final String str, final String suffix) { return endsWith(str, suffix, true); } /** * Checks if the given string ends with any of the specified substrings. * * @param str the string to be checked, may be {@code null} or empty * @param substrs the array of substrings to be checked * @return {@code true} if the string ends with any of the specified substrings, {@code false} otherwise */ @SafeVarargs public static boolean endsWithAny(final String str, final String... substrs) { if (str == null || N.isEmpty(substrs)) { return false; } for (final String searchString : substrs) { if (endsWith(str, searchString)) { return true; } } return false; } /** * Checks if the given string ends with any of the specified substrings, ignoring case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param substrs the array of substrings to be checked * @return {@code true} if the string ends with any of the specified substrings, ignoring case considerations, {@code false} otherwise */ public static boolean endsWithAnyIgnoreCase(final String str, final String... substrs) { if (str == null || N.isEmpty(substrs)) { return false; } for (final String searchString : substrs) { if (endsWithIgnoreCase(str, searchString)) { return true; } } return false; } /** * Checks if the given string ends with the specified suffix, with an option to ignore case considerations. * * @param str the string to be checked, may be {@code null} or empty * @param suffix the suffix to be checked * @param ignoreCase if {@code true}, the comparison is case-insensitive * @return {@code true} if the string ends with the specified suffix, considering the case sensitivity option, {@code false} otherwise */ private static boolean endsWith(final String str, final String suffix, final boolean ignoreCase) { if (str == null || suffix == null || suffix.length() > str.length()) { return false; } final int strOffset = str.length() - suffix.length(); return ignoreCase ? str.regionMatches(true, strOffset, suffix, 0, suffix.length()) : str.endsWith(suffix); } /** * Compares two strings for equality. * * @param a the first string to compare, may be null * @param b the second string to compare, may be null * @return {@code true} if the strings are equal, {@code false} otherwise */ public static boolean equals(final String a, final String b) { return (a == null) ? b == null : (b != null && a.length() == b.length() && a.equals(b)); } /** * Compares two strings for equality, ignoring case considerations. * * @param a the first string to compare, may be null * @param b the second string to compare, may be null * @return {@code true} if the strings are equal, ignoring case considerations, {@code false} otherwise */ public static boolean equalsIgnoreCase(final String a, final String b) { return (a == null) ? b == null : (a.equalsIgnoreCase(b)); } /** * Checks if the given string is equal to any of the specified search strings. * * @param str the string to be checked, may be null * @param searchStrings the array of strings to compare against, may be {@code null} or empty * @return {@code true} if the string is equal to any of the specified search strings, {@code false} otherwise */ @SafeVarargs public static boolean equalsAny(final String str, final String... searchStrings) { if (N.isEmpty(searchStrings)) { return false; } for (final String searchString : searchStrings) { if (equals(str, searchString)) { return true; } } return false; } /** * Checks if the given string is equal to any of the specified search strings, ignoring case considerations. * * @param str the string to be checked, may be null * @param searchStrs the array of strings to compare against, may be {@code null} or empty * @return {@code true} if the string is equal to any of the specified search strings, ignoring case considerations, {@code false} otherwise */ @SafeVarargs public static boolean equalsAnyIgnoreCase(final String str, final String... searchStrs) { if (N.isEmpty(searchStrs)) { return false; } else if (searchStrs.length == 1) { return equalsIgnoreCase(str, searchStrs[0]); } else if (searchStrs.length == 2) { if (equalsIgnoreCase(str, searchStrs[0])) { return true; } return equalsIgnoreCase(str, searchStrs[1]); } final String sourceText = str.toLowerCase(); for (final String searchStr : searchStrs) { if (equals(sourceText, searchStr.toLowerCase())) { return true; } } return false; } /** * Compares two strings lexicographically, ignoring case considerations. Null is considered less than any string. * * @param a the first string to compare, may be null * @param b the second string to compare, may be null * @return a negative integer, zero, or a positive integer as the first string is less than, equal to, or greater than the second string, ignoring case considerations */ public static int compareIgnoreCase(final String a, final String b) { return a == null ? (b == null ? 0 : -1) : (b == null ? 1 : a.compareToIgnoreCase(b)); } /** *

    * Compares two Strings, and returns the index at which the Strings begin * to differ. *

    * *

    * For example, * {@code indexOfDifference("i am a machine", "i am a robot") -> 7} *

    * *
         * Strings.indexOfDifference(null, null) = -1
         * Strings.indexOfDifference("", "") = -1
         * Strings.indexOfDifference("", "abc") = 0
         * Strings.indexOfDifference("abc", "") = 0
         * Strings.indexOfDifference("abc", "abc") = -1
         * Strings.indexOfDifference("ab", "abxyz") = 2
         * Strings.indexOfDifference("abcde", "abxyz") = 2
         * Strings.indexOfDifference("abcde", "xyz") = 0
         * 
    * * @param a * the first String, may be null * @param b * the second String, may be null * @return */ public static int indexOfDifference(final String a, final String b) { if (N.equals(a, b) || (isEmpty(a) && isEmpty(b))) { return N.INDEX_NOT_FOUND; } if (isEmpty(a) || isEmpty(b)) { return 0; } int i = 0; for (final int len = N.min(a.length(), b.length()); i < len; i++) { if (a.charAt(i) != b.charAt(i)) { break; } } if (i < b.length() || i < a.length()) { return i; } return N.INDEX_NOT_FOUND; } /** *

    * Compares all Strings in an array and returns the index at which the * Strings begin to differ. *

    * *

    * For example, * indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7 *

    * *
         * Strings.indexOfDifference(null) = -1
         * Strings.indexOfDifference(new String[] {}) = -1
         * Strings.indexOfDifference(new String[] {"abc"}) = -1
         * Strings.indexOfDifference(new String[] {null, null}) = -1
         * Strings.indexOfDifference(new String[] {"", ""}) = -1
         * Strings.indexOfDifference(new String[] {"", null}) = -1
         * Strings.indexOfDifference(new String[] {"abc", {@code null}, null}) = 0
         * Strings.indexOfDifference(new String[] {null, {@code null}, "abc"}) = 0
         * Strings.indexOfDifference(new String[] {"", "abc"}) = 0
         * Strings.indexOfDifference(new String[] {"abc", ""}) = 0
         * Strings.indexOfDifference(new String[] {"abc", "abc"}) = -1
         * Strings.indexOfDifference(new String[] {"abc", "a"}) = 1
         * Strings.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
         * Strings.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
         * Strings.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
         * Strings.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
         * Strings.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
         * 
    * * @param strs * array of Strings, entries may be null * @return * equal or null/empty */ @SafeVarargs public static int indexOfDifference(final String... strs) { if (N.isEmpty(strs) || strs.length == 1) { return N.INDEX_NOT_FOUND; } final int arrayLen = strs.length; int shortestStrLen = Integer.MAX_VALUE; int longestStrLen = 0; // find the min and max string lengths; this avoids checking to make // sure we are not exceeding the length of the string each time through // the bottom loop. for (final String str : strs) { if (str == null) { shortestStrLen = 0; } else { shortestStrLen = Math.min(str.length(), shortestStrLen); longestStrLen = Math.max(str.length(), longestStrLen); } } // handle lists containing all nulls or all empty strings if (longestStrLen == 0) { return N.INDEX_NOT_FOUND; } if (shortestStrLen == 0) { return 0; } // find the position with the first difference across all strings int firstDiff = -1; char comparisonChar = 0; for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { comparisonChar = strs[0].charAt(stringPos); for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { if (strs[arrayPos].charAt(stringPos) != comparisonChar) { firstDiff = stringPos; break; } } if (firstDiff != -1) { break; } } if (firstDiff == -1 && shortestStrLen != longestStrLen) { // we compared all the characters up to the length of the // shortest string and didn't find a match, but the string lengths // vary, so return the length of the shortest string. return shortestStrLen; } return firstDiff; } // --------- from Google Guava /** * Returns the length of the common prefix between two CharSequences. * If either CharSequence is empty, returns 0. * * @param a the first CharSequence to compare, may be null * @param b the second CharSequence to compare, may be null * @return the length of the common prefix, or 0 if either CharSequence is empty */ public static int lengthOfCommonPrefix(final CharSequence a, final CharSequence b) { if (isEmpty(a) || isEmpty(b)) { return 0; } final int maxPrefixLength = Math.min(a.length(), b.length()); int cnt = 0; while (cnt < maxPrefixLength && a.charAt(cnt) == b.charAt(cnt)) { cnt++; } if (validSurrogatePairAt(a, cnt - 1) || validSurrogatePairAt(b, cnt - 1)) { cnt--; } return cnt; } /** * Returns the length of the common suffix between two CharSequences. * If either CharSequence is empty, returns 0. * * @param a the first CharSequence to compare, may be null * @param b the second CharSequence to compare, may be null * @return the length of the common suffix, or 0 if either CharSequence is empty */ public static int lengthOfCommonSuffix(final CharSequence a, final CharSequence b) { if (isEmpty(a) || isEmpty(b)) { return 0; } final int aLength = a.length(); final int bLength = b.length(); final int maxSuffixLength = Math.min(aLength, bLength); int cnt = 0; while (cnt < maxSuffixLength && a.charAt(aLength - cnt - 1) == b.charAt(bLength - cnt - 1)) { cnt++; } if (validSurrogatePairAt(a, aLength - cnt - 1) || validSurrogatePairAt(b, bLength - cnt - 1)) { cnt--; } return cnt; } /** * Note: copy from Google Guava under Apache License v2 * * Returns the longest string {@code prefix} such that * {@code a.toString().startsWith(prefix) && b.toString().startsWith(prefix)} * , taking care not to split surrogate pairs. If {@code a} and {@code b} * have no common prefix, returns the empty string. * * @param a the first CharSequence to compare * @param b the second CharSequence to compare * @return the longest common prefix, or an empty string if there is no common prefix */ public static String commonPrefix(final CharSequence a, final CharSequence b) { if (isEmpty(a) || isEmpty(b)) { return EMPTY_STRING; } final int commonPrefixLen = lengthOfCommonPrefix(a, b); if (commonPrefixLen == a.length()) { return a.toString(); } else if (commonPrefixLen == b.length()) { return b.toString(); } else { return a.subSequence(0, commonPrefixLen).toString(); } } /** * Returns the longest common prefix among an array of CharSequences. * If the array is empty, the method will return an empty string. * If any CharSequence is empty or {@code null}, the method will return an empty string. * * @param strs The array of CharSequences to compare. * @return The longest common prefix among the given CharSequences. Returns an empty string if the array is empty or any CharSequence is empty or {@code null}. */ @SafeVarargs public static String commonPrefix(final CharSequence... strs) { if (N.isEmpty(strs)) { return EMPTY_STRING; } if (strs.length == 1) { return isEmpty(strs[0]) ? EMPTY_STRING : strs[0].toString(); } else if (isAnyEmpty(strs)) { return EMPTY_STRING; } String commonPrefix = commonPrefix(strs[0], strs[1]); if (isEmpty(commonPrefix)) { return EMPTY_STRING; } for (int i = 2, len = strs.length; i < len; i++) { commonPrefix = commonPrefix(commonPrefix, strs[i]); if (isEmpty(commonPrefix)) { return commonPrefix; } } return commonPrefix; } /** * Note: copy from Google Guava under Apache License v2 * * Returns the longest string {@code suffix} such that * {@code a.toString().endsWith(suffix) && b.toString().endsWith(suffix)}, * taking care not to split surrogate pairs. If {@code a} and {@code b} have * no common suffix, returns the empty string. * * @param a the first CharSequence to compare * @param b the second CharSequence to compare * @return the longest common suffix, or an empty string if there is no common suffix */ public static String commonSuffix(final CharSequence a, final CharSequence b) { if (isEmpty(a) || isEmpty(b)) { return EMPTY_STRING; } final int aLength = a.length(); final int commonSuffixLen = lengthOfCommonSuffix(a, b); if (commonSuffixLen == aLength) { return a.toString(); } else if (commonSuffixLen == b.length()) { return b.toString(); } else { return a.subSequence(aLength - commonSuffixLen, aLength).toString(); } } /** * Returns the longest common suffix between the given CharSequences. * If any CharSequence is empty or {@code null}, the method will return an empty string. * * @param strs The CharSequences to compare. * @return The longest common suffix between the given CharSequences. Returns an empty string if any CharSequence is empty or {@code null}. */ @SafeVarargs public static String commonSuffix(final CharSequence... strs) { if (N.isEmpty(strs)) { return EMPTY_STRING; } if (strs.length == 1) { return isEmpty(strs[0]) ? EMPTY_STRING : strs[0].toString(); } else if (isAnyEmpty(strs)) { return EMPTY_STRING; } String commonSuffix = commonSuffix(strs[0], strs[1]); if (isEmpty(commonSuffix)) { return EMPTY_STRING; } for (int i = 2, len = strs.length; i < len; i++) { commonSuffix = commonSuffix(commonSuffix, strs[i]); if (isEmpty(commonSuffix)) { return commonSuffix; } } return commonSuffix; } // --------- from Google Guava /** * Note: copy from Google Guava under Apache License v2 * * True when a valid surrogate pair starts at the given {@code index} in the * given {@code string}. Out-of-range indexes return {@code false}. * * @param str * @param index * @return */ static boolean validSurrogatePairAt(final CharSequence str, final int index) { return index >= 0 && index <= (str.length() - 2) && Character.isHighSurrogate(str.charAt(index)) && Character.isLowSurrogate(str.charAt(index + 1)); } /** * Returns the longest common substring between two given CharSequences. * If either CharSequence is empty or {@code null}, the method will return an empty string. * * @param a The first CharSequence. * @param b The second CharSequence. * @return an empty String {@code ""} is {@code a} or {@code b} is empty or {@code null}. */ public static String longestCommonSubstring(final CharSequence a, final CharSequence b) { if (isEmpty(a) || isEmpty(b)) { return EMPTY_STRING; } final int lenA = N.len(a); final int lenB = N.len(b); char[] charsToCheck = null; if (lenA < lenB) { charsToCheck = a.toString().toCharArray(); } else { charsToCheck = b.toString().toCharArray(); } checkInputChars(charsToCheck, lenA < lenB ? "a" : "b", true); final int[] dp = new int[lenB + 1]; int endIndex = 0; int maxLen = 0; if (lenA > 16 || lenB > 16) { final char[] chsA = lenA < lenB ? charsToCheck : a.toString().toCharArray(); final char[] chsB = lenA < lenB ? b.toString().toCharArray() : charsToCheck; for (int i = 1; i <= lenA; i++) { for (int j = lenB; j > 0; j--) { if (chsA[i - 1] == chsB[j - 1]) { dp[j] = 1 + dp[j - 1]; if (dp[j] > maxLen) { maxLen = dp[j]; endIndex = i; } } else { dp[j] = 0; } } } } else { for (int i = 1; i <= lenA; i++) { for (int j = lenB; j > 0; j--) { if (a.charAt(i - 1) == b.charAt(j - 1)) { dp[j] = 1 + dp[j - 1]; if (dp[j] > maxLen) { maxLen = dp[j]; endIndex = i; } } else { dp[j] = 0; } } } } if (maxLen == 0) { return EMPTY_STRING; } return a.subSequence(endIndex - maxLen, endIndex).toString(); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length())}, * otherwise returns: {@code str.substring(inclusiveBeginIndex)}. * * @param str * @param inclusiveBeginIndex * @return * @see StrUtil#substring(String, int) * @see #substring(String, int, int) * @see #substringAfter(String, char) */ @MayReturnNull public static String substring(final String str, final int inclusiveBeginIndex) { if (str == null || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length()) { return null; } return str.substring(inclusiveBeginIndex); } // /** // * Returns {@code null} which means it doesn't exist if {@code (str == null || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length())}, // * otherwise returns: {@code str.substring(inclusiveBeginIndex)}. // * // * @param str // * @param inclusiveBeginIndex // * @return // * @see #substring(String, int) // * @see StrUtil#substring(String, int) // * @see #substring(String, int, int) // * @see #largestSubstring(String, int, int) // */ // @MayReturnNull // public static String substringAfter(String str, int inclusiveBeginIndex) { // if (str == null || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length()) { // return null; // } // // return str.substring(inclusiveBeginIndex); // } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || inclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || inclusiveBeginIndex > exclusiveEndIndex || inclusiveBeginIndex > str.length())}, * otherwise returns: {@code str.substring(inclusiveBeginIndex, min(exclusiveEndIndex, str.length()))}. * * @param str * @param inclusiveBeginIndex * @param exclusiveEndIndex * @return * @see StrUtil#substring(String, int, int) */ @MayReturnNull public static String substring(final String str, final int inclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || inclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || inclusiveBeginIndex > exclusiveEndIndex || inclusiveBeginIndex > str.length()) { return null; } return str.substring(inclusiveBeginIndex, N.min(exclusiveEndIndex, str.length())); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || inclusiveBeginIndex < 0)}, or {@code funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) < 0}. * * @param str * @param inclusiveBeginIndex * @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) if inclusiveBeginIndex >= 0} * @return * @see StrUtil#substring(String, int, IntUnaryOperator) * @see #substring(String, int, int) */ @MayReturnNull public static String substring(final String str, final int inclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { if (str == null || inclusiveBeginIndex < 0) { return null; } return substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex)); } // /** // * Returns {@code null} which means it doesn't exist if {@code (str == null || inclusiveBeginIndex < 0)}, or {@code funcOfExclusiveEndIndex.apply(str, inclusiveBeginIndex) < 0}. // * // * @param str // * @param inclusiveBeginIndex // * @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.apply(str, inclusiveBeginIndex) if inclusiveBeginIndex >= 0} // * @return {@code null} if {@code (str == null || inclusiveBeginIndex < 0)}. (auto-generated java doc for return) // * @see #substring(String, int, int) // */ // @MayReturnNull // @Beta // public static String substring(final String str, final int inclusiveBeginIndex, final BiFunction funcOfExclusiveEndIndex) { // if (str == null || inclusiveBeginIndex < 0) { // return null; // } // // return substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex.apply(str, inclusiveBeginIndex)); // } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || exclusiveEndIndex < 0)}, or {@code funcOfInclusiveBeginIndex.applyAsInt(exclusiveEndIndex) < 0}. * * * @param str * @param funcOfInclusiveBeginIndex {@code inclusiveBeginIndex <- funcOfInclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) if exclusiveEndIndex > 0} * @param exclusiveEndIndex * @return * @see StrUtil#substring(String, IntUnaryOperator, int) * @see #substring(String, int, int) */ @MayReturnNull public static String substring(final String str, final IntUnaryOperator funcOfInclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || exclusiveEndIndex < 0) { return null; } return substring(str, funcOfInclusiveBeginIndex.applyAsInt(exclusiveEndIndex), exclusiveEndIndex); } // /** // * Returns {@code null} which means it doesn't exist if {@code (str == null || exclusiveEndIndex < 0)}, or {@code funcOfInclusiveBeginIndex.apply(str, exclusiveEndIndex) < 0}. // * // * // * @param str // * @param funcOfInclusiveBeginIndex {@code inclusiveBeginIndex <- funcOfInclusiveBeginIndex.apply(str, exclusiveEndIndex)) if exclusiveEndIndex > 0} // * @param exclusiveEndIndex // * @return {@code null} if {@code (str == null || exclusiveEndIndex < 0)}. (auto-generated java doc for return) // * @see #substring(String, int, int) // */ // @MayReturnNull // @Beta // public static String substring(final String str, final BiFunction funcOfInclusiveBeginIndex, final int exclusiveEndIndex) { // if (str == null || exclusiveEndIndex < 0) { // return null; // } // // return substring(str, funcOfInclusiveBeginIndex.apply(str, exclusiveEndIndex), exclusiveEndIndex); // } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || str.length() == 0)}, or {@code str.indexOf(delimiterOfInclusiveBeginIndex) < 0}, * otherwise returns: {@code str.substring(str.indexOf(delimiterOfInclusiveBeginIndex))}. * * @param str * @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.indexOf(delimiterOfInclusiveBeginIndex)} * @return * @see #substringAfter(String, char) * @deprecated */ @MayReturnNull @Deprecated public static String substring(final String str, final char delimiterOfInclusiveBeginIndex) { if (str == null || str.isEmpty()) { return null; } return substring(str, str.indexOf(delimiterOfInclusiveBeginIndex)); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || delimiterOfInclusiveBeginIndex == null)}, or {@code str.indexOf(delimiterOfInclusiveBeginIndex) < 0}, * otherwise returns: {@code str.substring(str.indexOf(delimiterOfInclusiveBeginIndex))}. * * @param str * @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.indexOf(delimiterOfInclusiveBeginIndex)} * @return * @see #substringAfter(String, String) * @deprecated */ @MayReturnNull @Deprecated public static String substring(final String str, final String delimiterOfInclusiveBeginIndex) { if (str == null || delimiterOfInclusiveBeginIndex == null) { return null; } if (delimiterOfInclusiveBeginIndex.isEmpty()) { return str; } return substring(str, str.indexOf(delimiterOfInclusiveBeginIndex)); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || str.length() == 0 || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length())}, or {@code str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1)}. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex {@code str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1)} * @return * @see #substring(String, int, int) * @deprecated */ @MayReturnNull @Deprecated public static String substring(final String str, final int inclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { if (str == null || str.isEmpty() || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length()) { return null; } final int index = str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1); // inconsistant behavior // if (index < 0 && str.charAt(inclusiveBeginIndex) == delimiterOfExclusiveEndIndex) { // return EMPTY_STRING; // } return substring(str, inclusiveBeginIndex, index); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || delimiterOfExclusiveEndIndex == {@code null} || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length())}, or {@code str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1) < 0}. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex {@code exclusiveEndIndex <- str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1) if inclusiveBeginIndex >= 0} * @return * @see #substring(String, int, int) * @deprecated */ @MayReturnNull @Deprecated public static String substring(final String str, final int inclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length()) { return null; } if (delimiterOfExclusiveEndIndex.isEmpty()) { return EMPTY_STRING; } return substring(str, inclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1)); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || str.length() == 0 || exclusiveEndIndex < 0)}, or {@code str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) < 0}. * * @param str * @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) if exclusiveEndIndex > 0} * @param exclusiveEndIndex * @return * @see #substring(String, int, int) * @deprecated */ @MayReturnNull @Deprecated public static String substring(final String str, final char delimiterOfInclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || str.isEmpty() || exclusiveEndIndex < 0) { return null; } return substring(str, str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1), exclusiveEndIndex); } /** * Returns {@code null} which means it doesn't exist if {@code (str == {@code null} || delimiterOfInclusiveBeginIndex == {@code null} || exclusiveEndIndex < 0)}, or {@code str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - 1) < 0}. * * * @param str * @param delimiterOfInclusiveBeginIndex {@code inclusiveBeginIndex <- str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - exclusiveEndIndex - delimiterOfInclusiveBeginIndex.length()) if exclusiveEndIndex > 0} * @param exclusiveEndIndex * @return * @see #substring(String, int, int) * @deprecated */ @MayReturnNull @Deprecated public static String substring(final String str, final String delimiterOfInclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || delimiterOfInclusiveBeginIndex == null || exclusiveEndIndex < 0) { return null; } if (delimiterOfInclusiveBeginIndex.isEmpty()) { return EMPTY_STRING; } return substring(str, str.lastIndexOf(delimiterOfInclusiveBeginIndex, exclusiveEndIndex - delimiterOfInclusiveBeginIndex.length()), exclusiveEndIndex); } /** * Returns the substring after first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveBeginIndex * @return */ @MayReturnNull public static String substringAfter(final String str, final char delimiterOfExclusiveBeginIndex) { if (str == null || str.isEmpty()) { return null; } final int index = str.indexOf(delimiterOfExclusiveBeginIndex); if (index < 0) { return null; } return str.substring(index + 1); } /** * Returns the substring after first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveBeginIndex * @return */ @MayReturnNull public static String substringAfter(final String str, final String delimiterOfExclusiveBeginIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null) { return null; } if (delimiterOfExclusiveBeginIndex.isEmpty()) { return str; } final int index = str.indexOf(delimiterOfExclusiveBeginIndex); if (index < 0) { return null; } return str.substring(index + delimiterOfExclusiveBeginIndex.length()); } /** * Returns {@code null} which means it doesn't exist if {@code str == {@code null} || delimiterOfExclusiveBeginIndex == {@code null} || exclusiveEndIndex < 0}, or {@code str.indexOf(delimiterOfExclusiveBeginIndex) < 0 || str.indexOf(delimiterOfExclusiveBeginIndex) + delimiterOfExclusiveBeginIndex.length() > exclusiveEndIndex} * otherwise returns {@code substring(str, index + delimiterOfExclusiveBeginIndex.length(), exclusiveEndIndex)}; * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return */ @MayReturnNull public static String substringAfter(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null || exclusiveEndIndex < 0) { return null; } if (delimiterOfExclusiveBeginIndex.isEmpty()) { return substring(str, 0, exclusiveEndIndex); } else if (exclusiveEndIndex == 0) { return null; } final int index = str.indexOf(delimiterOfExclusiveBeginIndex); if (index < 0 || index + delimiterOfExclusiveBeginIndex.length() > exclusiveEndIndex) { return null; } return substring(str, index + delimiterOfExclusiveBeginIndex.length(), exclusiveEndIndex); } /** * Returns the substring after last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveBeginIndex * @return */ @MayReturnNull public static String substringAfterLast(final String str, final char delimiterOfExclusiveBeginIndex) { if (str == null || str.isEmpty()) { return null; } final int index = str.lastIndexOf(delimiterOfExclusiveBeginIndex); if (index < 0) { return null; } return str.substring(index + 1); } /** * Returns the substring after last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveBeginIndex * @return */ @MayReturnNull public static String substringAfterLast(final String str, final String delimiterOfExclusiveBeginIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null) { return null; } if (delimiterOfExclusiveBeginIndex.isEmpty()) { return EMPTY_STRING; } final int index = str.lastIndexOf(delimiterOfExclusiveBeginIndex); if (index < 0) { return null; } return str.substring(index + delimiterOfExclusiveBeginIndex.length()); } /** * Returns the substring after last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return */ @MayReturnNull public static String substringAfterLast(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null || exclusiveEndIndex < 0) { return null; } if (delimiterOfExclusiveBeginIndex.isEmpty()) { return EMPTY_STRING; } else if (exclusiveEndIndex == 0) { return null; } final int index = str.lastIndexOf(delimiterOfExclusiveBeginIndex, exclusiveEndIndex - delimiterOfExclusiveBeginIndex.length()); if (index < 0 || index + delimiterOfExclusiveBeginIndex.length() > exclusiveEndIndex) { return null; } return str.substring(index + delimiterOfExclusiveBeginIndex.length(), exclusiveEndIndex); } /** * Returns the substring before any of {@code delimitersOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimitersOfExclusiveBeginIndex * @return * @see #substringAfter(String, String) */ @MayReturnNull public static String substringAfterAny(final String str, final char... delimitersOfExclusiveBeginIndex) { checkInputChars(delimitersOfExclusiveBeginIndex, cs.delimitersOfExclusiveBeginIndex, true); if (str == null || N.isEmpty(delimitersOfExclusiveBeginIndex)) { return null; } int index = -1; for (final char delimiterOfExclusiveBeginIndex : delimitersOfExclusiveBeginIndex) { index = str.indexOf(delimiterOfExclusiveBeginIndex); if (index >= 0) { return str.substring(index + 1); } } return null; } /** * Returns the substring before any of {@code delimitersOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimitersOfExclusiveBeginIndex * @return * @see #substringAfter(String, String) */ @MayReturnNull public static String substringAfterAny(final String str, final String... delimitersOfExclusiveBeginIndex) { if (str == null || N.isEmpty(delimitersOfExclusiveBeginIndex)) { return null; } String substr = null; for (final String delimiterOfExclusiveBeginIndex : delimitersOfExclusiveBeginIndex) { substr = substringAfter(str, delimiterOfExclusiveBeginIndex); if (substr != null) { return substr; } } return null; } /** * Returns the substring before first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveEndIndex * @return */ @MayReturnNull public static String substringBefore(final String str, final char delimiterOfExclusiveEndIndex) { if (str == null) { return null; } final int index = str.indexOf(delimiterOfExclusiveEndIndex); if (index < 0) { return null; } return str.substring(0, index); } /** * Returns the substring before first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveEndIndex * @return */ @MayReturnNull public static String substringBefore(final String str, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null) { return null; } if (delimiterOfExclusiveEndIndex.isEmpty()) { return EMPTY_STRING; } final int endIndex = str.indexOf(delimiterOfExclusiveEndIndex); if (endIndex < 0) { return null; } return str.substring(0, endIndex); } /** * Returns the substring before first {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ @MayReturnNull public static String substringBefore(final String str, final int inclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length()) { return null; } if (delimiterOfExclusiveEndIndex.isEmpty()) { return EMPTY_STRING; } else if (inclusiveBeginIndex == str.length()) { return null; } final int index = str.indexOf(delimiterOfExclusiveEndIndex, inclusiveBeginIndex + 1); if (index < 0) { return null; } return str.substring(inclusiveBeginIndex, index); } /** * Returns the substring before last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveEndIndex * @return */ @MayReturnNull public static String substringBeforeLast(final String str, final char delimiterOfExclusiveEndIndex) { if (str == null || str.isEmpty()) { return null; } final int index = str.lastIndexOf(delimiterOfExclusiveEndIndex); if (index < 0) { return null; } return str.substring(0, index); } /** * Returns the substring before last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimiterOfExclusiveEndIndex * @return */ @MayReturnNull public static String substringBeforeLast(final String str, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null) { return null; } if (delimiterOfExclusiveEndIndex.isEmpty()) { return str; } final int index = str.lastIndexOf(delimiterOfExclusiveEndIndex); if (index < 0) { return null; } return str.substring(0, index); } /** * Returns the substring before last {@code delimiterOfExclusiveBeginIndex} if it exists, otherwise return {@code null} String. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ @MayReturnNull public static String substringBeforeLast(final String str, final int inclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null || inclusiveBeginIndex < 0 || inclusiveBeginIndex > str.length()) { return null; } if (delimiterOfExclusiveEndIndex.isEmpty()) { return str.substring(inclusiveBeginIndex); } else if (inclusiveBeginIndex == str.length()) { return null; } final int index = str.lastIndexOf(delimiterOfExclusiveEndIndex); if (index < 0 || index < inclusiveBeginIndex) { return null; } return str.substring(inclusiveBeginIndex, index); } /** * Returns the substring before any of {@code delimitersOfExclusiveEndIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimitersOfExclusiveEndIndex * @return * @see #substringBefore(String, String) */ @MayReturnNull public static String substringBeforeAny(final String str, final char... delimitersOfExclusiveEndIndex) { checkInputChars(delimitersOfExclusiveEndIndex, cs.delimitersOfExclusiveEndIndex, true); if (str == null || N.isEmpty(delimitersOfExclusiveEndIndex)) { return null; } int index = -1; for (final char delimiterOfExclusiveEndIndex : delimitersOfExclusiveEndIndex) { index = str.indexOf(delimiterOfExclusiveEndIndex); if (index >= 0) { return str.substring(0, index); } } return null; } /** * Returns the substring before any of {@code delimitersOfExclusiveEndIndex} if it exists, otherwise return {@code null} String. * * @param str * @param delimitersOfExclusiveEndIndex * @return * @see #substringBefore(String, String) */ @MayReturnNull public static String substringBeforeAny(final String str, final String... delimitersOfExclusiveEndIndex) { if (str == null || N.isEmpty(delimitersOfExclusiveEndIndex)) { return null; } String substr = null; for (final String delimiterOfExclusiveEndIndex : delimitersOfExclusiveEndIndex) { substr = substringBefore(str, delimiterOfExclusiveEndIndex); if (substr != null) { return substr; } } return null; } /** * Returns {@code null} which means it doesn't exist if {@code str == {@code null} || exclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || exclusiveBeginIndex >= exclusiveEndIndex || exclusiveBeginIndex >= str.length()}, * Otherwise returns: {@code str.substring(exclusiveBeginIndex + 1, min(exclusiveEndIndex, str.length()))}. * * @param str * @param exclusiveBeginIndex * @param exclusiveEndIndex * @return */ @MayReturnNull public static String substringBetween(final String str, final int exclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || exclusiveBeginIndex < 0 || exclusiveEndIndex < 0 || exclusiveBeginIndex >= exclusiveEndIndex || exclusiveBeginIndex >= str.length()) { return null; } return str.substring(exclusiveBeginIndex + 1, N.min(exclusiveEndIndex, str.length())); } /** * * @param str * @param exclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final int exclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { if (str == null || exclusiveBeginIndex < 0 || exclusiveBeginIndex >= str.length()) { return null; } return substringBetween(str, exclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, exclusiveBeginIndex + 1)); } /** * * @param str * @param exclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final int exclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null || exclusiveBeginIndex < 0 || exclusiveBeginIndex >= str.length()) { return null; } return substringBetween(str, exclusiveBeginIndex, str.indexOf(delimiterOfExclusiveEndIndex, exclusiveBeginIndex + 1)); } /** * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final char delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || exclusiveEndIndex <= 0) { return null; } return substringBetween(str, str.indexOf(delimiterOfExclusiveBeginIndex), exclusiveEndIndex); } /** * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null || exclusiveEndIndex < 0) { return null; } final int index = str.indexOf(delimiterOfExclusiveBeginIndex); if (index < 0) { return null; } final int exclusiveBeginIndex = index + delimiterOfExclusiveBeginIndex.length(); if (exclusiveBeginIndex > exclusiveEndIndex) { return null; } return str.substring(exclusiveBeginIndex, exclusiveEndIndex); } /** * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final char delimiterOfExclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { if (str == null || str.length() <= 1) { return null; } int startIndex = str.indexOf(delimiterOfExclusiveBeginIndex); if (startIndex < 0) { return null; } // even delimiterOfExclusiveBeginIndex and delimiterOfExclusiveEndIndex are equal, but should consider them as different chars. see: substringBetween(String str, String tag) // if (delimiterOfExclusiveBeginIndex == delimiterOfExclusiveEndIndex) { // return EMPTY_STRING; // } startIndex += 1; final int endIndex = str.indexOf(delimiterOfExclusiveEndIndex, startIndex); if (endIndex < 0) { return null; } return str.substring(startIndex, endIndex); } /** * * @param str * @param tag * @return * @see #substringBetween(String, String, String) * @see #substringBetween(String, int, int) */ public static String substringBetween(final String str, final String tag) { return substringBetween(str, tag, tag); } /** * Returns a substring from the given string that is between the two specified delimiters. * The substring does not include the delimiters themselves. * If the delimiters are not found, this method will return {@code null}. * * @param str The string from which to extract the substring. * @param delimiterOfExclusiveBeginIndex The delimiter after which the substring starts. * @param delimiterOfExclusiveEndIndex The delimiter before which the substring ends. * @return The substring between the two delimiters. Returns {@code null} if the delimiters are not found. */ public static String substringBetween(final String str, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return substringBetween(str, 0, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); } /** * * @param str * @param fromIndex start index for {@code delimiterOfExclusive}. {@code str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex)} * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final int fromIndex, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null || delimiterOfExclusiveEndIndex == null || fromIndex < 0 || fromIndex > str.length()) { return null; } int startIndex = fromIndex == 0 ? str.indexOf(delimiterOfExclusiveBeginIndex) : str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex); if (startIndex < 0) { return null; } startIndex += delimiterOfExclusiveBeginIndex.length(); final int endIndex = str.indexOf(delimiterOfExclusiveEndIndex, startIndex); if (endIndex < 0) { return null; } return str.substring(startIndex, endIndex); } /** * substringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]. * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ public static List substringsBetween(final String str, final char delimiterOfExclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { return isEmpty(str) ? new ArrayList<>() : substringsBetween(str, 0, str.length(), delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); } /** * Returns a list of substrings within the given string that are between the specified delimiters. * The substrings are found within the range specified by the fromIndex and toIndex parameters. * *
         * substringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a].
         * 
    * * @param str The string to be checked. May be {@code null} or empty. * @param fromIndex The starting index from where to check the string. * @param toIndex The ending index until where to check the string. * @param delimiterOfExclusiveBeginIndex The character that marks the beginning of a substring. * @param delimiterOfExclusiveEndIndex The character that marks the ending of a substring. * @return A list of substrings found between the specified delimiters. Returns an empty list if no such substrings are found. */ public static List substringsBetween(final String str, final int fromIndex, final int toIndex, final char delimiterOfExclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { final List substringIndices = substringIndicesBetween(str, fromIndex, toIndex, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); final List res = new ArrayList<>(substringIndices.size()); for (final int[] e : substringIndices) { res.add(str.substring(e[0], e[1])); } return res; } /** * substringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]. * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ public static List substringsBetween(final String str, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return isEmpty(str) ? new ArrayList<>() : substringsBetween(str, 0, str.length(), delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); } /** * substringsBetween("3[a2[c]]2[a]", '[', ']') = [a2[c], a]. * * @param str * @param fromIndex * @param toIndex * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ public static List substringsBetween(final String str, final int fromIndex, final int toIndex, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { final List substringIndices = substringIndicesBetween(str, fromIndex, toIndex, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); final List res = new ArrayList<>(substringIndices.size()); for (final int[] e : substringIndices) { res.add(str.substring(e[0], e[1])); } return res; } /** * * @param str * @param exclusiveBeginIndex * @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.applyAsInt(inclusiveBeginIndex) if inclusiveBeginIndex >= 0} * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final int exclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { if (str == null || exclusiveBeginIndex < 0 || exclusiveBeginIndex >= str.length()) { return null; } return substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex.applyAsInt(exclusiveBeginIndex)); } // /** // * // * @param str // * @param exclusiveBeginIndex // * @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.apply(str, exclusiveBeginIndex) if inclusiveBeginIndex >= 0} // * @return {@code null} if {@code (str == null || exclusiveBeginIndex < 0 || exclusiveBeginIndex >= str.length())}. (auto-generated java doc for return) // * @see #substringBetween(String, int, int) // */ // @MayReturnNull // @Beta // public static String substringBetween(String str, int exclusiveBeginIndex, final BiFunction funcOfExclusiveEndIndex) { // if (str == null || exclusiveBeginIndex < 0 || exclusiveBeginIndex >= str.length()) { // return null; // } // // return substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex.apply(str, exclusiveBeginIndex)); // } /** * * @param str * @param funcOfExclusiveBeginIndex {@code exclusiveBeginIndex <- funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) if exclusiveEndIndex >= 0} * @param exclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final IntUnaryOperator funcOfExclusiveBeginIndex, final int exclusiveEndIndex) { if (str == null || exclusiveEndIndex < 0) { return null; } return substringBetween(str, funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex), exclusiveEndIndex); } // /** // * // * @param str // * @param funcOfExclusiveBeginIndex {@code exclusiveBeginIndex <- funcOfExclusiveBeginIndex.apply(str, exclusiveEndIndex)) if exclusiveEndIndex >= 0} // * @param exclusiveEndIndex // * @return {@code null} if {@code (str == null || exclusiveEndIndex < 0)}. (auto-generated java doc for return) // * @see #substringBetween(String, int, int) // */ // @MayReturnNull // @Beta // public static String substringBetween(String str, final BiFunction funcOfExclusiveBeginIndex, int exclusiveEndIndex) { // if (str == null || exclusiveEndIndex < 0) { // return null; // } // // return substringBetween(str, funcOfExclusiveBeginIndex.apply(str, exclusiveEndIndex), exclusiveEndIndex); // } /** * * @param str * @param delimiterOfExclusiveBeginIndex * @param funcOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final String delimiterOfExclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveBeginIndex == null || delimiterOfExclusiveBeginIndex.length() > str.length()) { return null; } final int index = str.indexOf(delimiterOfExclusiveBeginIndex); if (index < 0) { return null; } final int exclusiveBeginIndex = index + delimiterOfExclusiveBeginIndex.length(); return substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex.applyAsInt(exclusiveBeginIndex)); } /** * Returns a substring from the given string, starting from a specified index and ending before a specified delimiter. * The starting index is determined by applying the provided IntUnaryOperator function on the ending index of the substring. * The ending index is the last occurrence of the specified delimiter in the string. * If the string or the delimiter is {@code null}, or if the delimiter's length is greater than the string's length, or if the ending index is less than 0, the method returns {@code null}. * * @param str The string from which to extract the substring. It can be {@code null}. * @param funcOfExclusiveBeginIndex The function to determine the starting index of the substring. It should not be {@code null}. * @param delimiterOfExclusiveEndIndex The delimiter before which the substring ends. It should not be {@code null}. * @return The extracted substring. Returns {@code null} if the input string is {@code null}, the function is {@code null}, the delimiter is {@code null}, the delimiter's length is greater than the string's length, or the ending index is less than 0. * @see #substringBetween(String, int, int) */ @MayReturnNull public static String substringBetween(final String str, final IntUnaryOperator funcOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || delimiterOfExclusiveEndIndex == null || delimiterOfExclusiveEndIndex.length() > str.length()) { return null; } final int exclusiveEndIndex = str.lastIndexOf(delimiterOfExclusiveEndIndex); if (exclusiveEndIndex < 0) { return null; } return substringBetween(str, funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex), exclusiveEndIndex); } /** * substringIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]. * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ public static List substringIndicesBetween(final String str, final char delimiterOfExclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { if (str == null || str.isEmpty()) { return new ArrayList<>(); } return substringIndicesBetween(str, 0, str.length(), delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); } /** * substringIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]. * * @param str * @param fromIndex * @param toIndex * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @throws IndexOutOfBoundsException */ public static List substringIndicesBetween(final String str, final int fromIndex, final int toIndex, final char delimiterOfExclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(str)); if (str == null || str.isEmpty()) { return new ArrayList<>(); } final List res = new ArrayList<>(); final int idx = str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex); if (idx < 0) { return res; } final Deque queue = new LinkedList<>(); char ch = 0; for (int i = idx; i < toIndex; i++) { ch = str.charAt(i); if (ch == delimiterOfExclusiveBeginIndex) { queue.push(i + 1); } else if (ch == delimiterOfExclusiveEndIndex && queue.size() > 0) { final int startIndex = queue.pop(); if (res.size() > 0 && startIndex < res.get(res.size() - 1)[0]) { while (res.size() > 0 && startIndex < res.get(res.size() - 1)[0]) { res.remove(res.size() - 1);//NOSONAR } } res.add(new int[] { startIndex, i }); } } return res; } /** * substringIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]. * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return */ public static List substringIndicesBetween(final String str, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { if (str == null || isEmpty(delimiterOfExclusiveBeginIndex) || isEmpty(delimiterOfExclusiveEndIndex)) { return new ArrayList<>(); } return substringIndicesBetween(str, 0, str.length(), delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex); } /** * substringIndicesBetween("3[a2[c]]2[a]", '[', ']') = [[2, 7], [10, 11]]. * * @param str * @param fromIndex * @param toIndex * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @throws IndexOutOfBoundsException */ public static List substringIndicesBetween(final String str, final int fromIndex, final int toIndex, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(str)); if (str == null || isEmpty(delimiterOfExclusiveBeginIndex) || isEmpty(delimiterOfExclusiveEndIndex)) { return new ArrayList<>(); } final List res = new ArrayList<>(); int idx = str.indexOf(delimiterOfExclusiveBeginIndex, fromIndex); if (idx < 0) { return res; } final Deque queue = new LinkedList<>(); queue.add(idx + delimiterOfExclusiveBeginIndex.length()); int next = -1; for (int i = idx + delimiterOfExclusiveBeginIndex.length(); i < toIndex;) { if (queue.size() == 0) { idx = next >= i ? next : str.indexOf(delimiterOfExclusiveBeginIndex, i); if (idx < 0) { break; } else { queue.add(idx + delimiterOfExclusiveBeginIndex.length()); i = idx + delimiterOfExclusiveBeginIndex.length(); } } idx = str.indexOf(delimiterOfExclusiveEndIndex, i); if (idx < 0) { break; } else { final int endIndex = idx; //noinspection DataFlowIssue idx = res.size() > 0 ? Math.max(res.get(res.size() - 1)[1] + delimiterOfExclusiveEndIndex.length(), queue.peekLast()) : queue.peekLast(); while ((idx = str.indexOf(delimiterOfExclusiveBeginIndex, idx)) >= 0 && idx < endIndex) { queue.push(idx + delimiterOfExclusiveBeginIndex.length()); idx = idx + delimiterOfExclusiveBeginIndex.length(); } if (idx > 0) { next = idx; } final int startIndex = queue.pop(); if (res.size() > 0 && startIndex < res.get(res.size() - 1)[0]) { while (res.size() > 0 && startIndex < res.get(res.size() - 1)[0]) { res.remove(res.size() - 1); } } res.add(new int[] { startIndex, endIndex }); i = endIndex + delimiterOfExclusiveEndIndex.length(); } } return res; } /** * Returns a new String with the specified range replaced with the replacement String. *
    * The original String remains unchanged. * * @param str the original string * @param fromIndex the initial index of the range to be replaced, inclusive * @param toIndex the final index of the range to be replaced, exclusive * @param replacement the string to replace the specified range in the original string * @return a new string with the specified range replaced by the replacement string. * @throws IndexOutOfBoundsException if the range is out of the string bounds * @see N#replaceRange(String, int, int, String) */ @Beta public static String replaceRange(final String str, final int fromIndex, final int toIndex, final String replacement) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(str)); if (N.isEmpty(str)) { return replacement == null ? EMPTY_STRING : replacement; } else if (fromIndex == toIndex && N.isEmpty(replacement)) { return str; } if (N.isEmpty(replacement)) { return str.substring(0, fromIndex) + str.substring(toIndex); } else { return str.substring(0, fromIndex) + N.nullToEmpty(replacement) + str.substring(toIndex); } } /** * Returns a new string with the specified range moved to the new position. *
    * The original String remains unchanged. * * @param str the original string to be modified * @param fromIndex the initial index of the range to be moved, inclusive * @param toIndex the final index of the range to be moved, exclusive * @param newPositionStartIndex must in the range: [0, String.length - (toIndex - fromIndex)] * @return a new string with the specified range moved to the new position. An empty String is returned if the specified String is {@code null} or empty. * @throws IndexOutOfBoundsException if the range is out of the string bounds or newPositionStartIndex is invalid * @see N#moveRange(String, int, int, int) */ @Beta public static String moveRange(final String str, final int fromIndex, final int toIndex, final int newPositionStartIndex) throws IndexOutOfBoundsException { final int len = N.len(str); N.checkIndexAndStartPositionForMoveRange(fromIndex, toIndex, newPositionStartIndex, len); if (N.isEmpty(str)) { return EMPTY_STRING; } if (fromIndex == toIndex || fromIndex == newPositionStartIndex) { return str; } if (newPositionStartIndex < fromIndex) { return Strings.concat(str.substring(0, newPositionStartIndex), str.substring(fromIndex, toIndex), str.substring(newPositionStartIndex, fromIndex), str.substring(toIndex)); } else { final int m = toIndex + (newPositionStartIndex - fromIndex); return Strings.concat(str.substring(0, fromIndex), str.substring(toIndex, m), str.substring(fromIndex, toIndex), str.substring(m)); } } /** * Returns a new String with the specified range of chars removed *
    * The original String remains unchanged. * * @param str the input string from which a range of characters are to be deleted * @param fromIndex the initial index of the range to be deleted, inclusive * @param toIndex the final index of the range to be deleted, exclusive * @return a new string with the specified range of characters deleted. An empty String is returned if the specified String is {@code null} or empty. * @throws IndexOutOfBoundsException if the range is out of the string bounds * @see N#deleteRange(String, int, int) */ @Beta public static String deleteRange(final String str, final int fromIndex, final int toIndex) throws IndexOutOfBoundsException { final int len = N.len(str); N.checkFromToIndex(fromIndex, toIndex, len); if (N.isEmpty(str)) { return EMPTY_STRING; } if (fromIndex == toIndex || fromIndex >= len) { return str; } else if (toIndex - fromIndex >= len) { return Strings.EMPTY_STRING; } return Strings.concat(str.substring(0, fromIndex) + str.substring(toIndex)); } /** * Returns the first character of the given string as an OptionalChar. * If the string is {@code null} or empty, an empty OptionalChar is returned. * * @param str the input string * @return an OptionalChar containing the first character of the string, or an empty OptionalChar if the string is {@code null} or empty */ public static OptionalChar firstChar(final String str) { if (str == null || str.isEmpty()) { return OptionalChar.empty(); } return OptionalChar.of(str.charAt(0)); } /** * Returns the last character of the given string as an OptionalChar. * If the string is {@code null} or empty, an empty OptionalChar is returned. * * @param str the input string * @return an OptionalChar containing the last character of the string, or an empty OptionalChar if the string is {@code null} or empty */ public static OptionalChar lastChar(final String str) { if (str == null || str.isEmpty()) { return OptionalChar.empty(); } return OptionalChar.of(str.charAt(str.length() - 1)); } /** * Returns at most first {@code n} chars of the specified {@code String} if its length is bigger than {@code n}, * or an empty String {@code ""} if {@code str} is empty or {@code null}, or itself it's length equal to or less than {@code n}. * * @param str * @param n * @return * @throws IllegalArgumentException */ @Beta public static String firstChars(final String str, final int n) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); if (str == null || str.isEmpty() || n == 0) { return EMPTY_STRING; } else if (str.length() <= n) { return str; } else { return str.substring(0, n); } } /** * Returns at most last {@code n} chars of the specified {@code String} if its length is bigger than {@code n}, * or an empty String {@code ""} if {@code str} is empty or {@code null}, or itself it's length equal to or less than {@code n}. * * @param str * @param n * @return * @throws IllegalArgumentException */ @Beta public static String lastChars(final String str, final int n) throws IllegalArgumentException { N.checkArgNotNegative(n, cs.n); if (str == null || str.isEmpty() || n == 0) { return EMPTY_STRING; } else if (str.length() <= n) { return str; } else { return str.substring(str.length() - n); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(boolean[], int, int, String, String, String) */ public static String join(final boolean[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(boolean[], int, int, String, String, String) */ public static String join(final boolean[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(boolean[], int, int, String, String, String) */ public static String join(final boolean[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(boolean[], int, int, String, String, String) */ public static String join(final boolean[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(boolean[], int, int, String, String, String) */ public static String join(final boolean[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 5 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final boolean[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 5 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(char[], int, int, String, String, String) */ public static String join(final char[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(char[], int, int, String, String, String) */ public static String join(final char[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(char[], int, int, String, String, String) */ public static String join(final char[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(char[], int, int, String, String, String) */ public static String join(final char[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 2)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(char[], int, int, String, String, String) */ public static String join(final char[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 1 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final char[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 1 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(byte[], int, int, String, String, String) */ public static String join(final byte[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(byte[], int, int, String, String, String) */ public static String join(final byte[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(byte[], int, int, String, String, String) */ public static String join(final byte[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(byte[], int, int, String, String, String) */ public static String join(final byte[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 5)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(byte[], int, int, String, String, String) */ public static String join(final byte[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 4 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final byte[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 4 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(short[], int, int, String, String, String) */ public static String join(final short[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(short[], int, int, String, String, String) */ public static String join(final short[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(short[], int, int, String, String, String) */ public static String join(final short[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(short[], int, int, String, String, String) */ public static String join(final short[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(short[], int, int, String, String, String) */ public static String join(final short[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 5 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final short[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 5 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(int[], int, int, String, String, String) */ public static String join(final int[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(int[], int, int, String, String, String) */ public static String join(final int[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(int[], int, int, String, String, String) */ public static String join(final int[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(int[], int, int, String, String, String) */ public static String join(final int[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 7)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(int[], int, int, String, String, String) */ public static String join(final int[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final int[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(long[], int, int, String, String, String) */ public static String join(final long[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(long[], int, int, String, String, String) */ public static String join(final long[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(long[], int, int, String, String, String) */ public static String join(final long[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(long[], int, int, String, String, String) */ public static String join(final long[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 7)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(long[], int, int, String, String, String) */ public static String join(final long[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final long[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(float[], int, int, String, String, String) */ public static String join(final float[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(float[], int, int, String, String, String) */ public static String join(final float[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(float[], int, int, String, String, String) */ public static String join(final float[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(float[], int, int, String, String, String) */ public static String join(final float[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 7)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(float[], int, int, String, String, String) */ public static String join(final float[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty and prefix'/'suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final float[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(double[], int, int, String, String, String) */ public static String join(final double[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(double[], int, int, String, String, String) */ public static String join(final double[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(double[], int, int, String, String, String) */ public static String join(final double[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(double[], int, int, String, String, String) */ public static String join(final double[] a, final int fromIndex, final int toIndex, final char delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 7)); try { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(double[], int, int, String, String, String) */ public static String join(final double[] a, final int fromIndex, final int toIndex, final String delimiter) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { return EMPTY_STRING; } else if (toIndex - fromIndex == 1) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter))); try { if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be empty. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final double[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return N.toString(a[fromIndex]); } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 6 + N.len(delimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } if (isEmpty(delimiter)) { for (int i = fromIndex; i < toIndex; i++) { sb.append(a[i]); } } else { for (int i = fromIndex; i < toIndex; i++) { if (i > fromIndex) { sb.append(delimiter); } sb.append(a[i]); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the elements of the provided array into a single String. * * @param a * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(Object[], String, String, String, boolean) */ public static String join(final Object[] a) { return join(a, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(Object[], String, String, String, boolean) */ public static String join(final Object[] a, final char delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty * @see #join(Object[], String, String, String, boolean) */ public static String join(final Object[] a, final String delimiter) { if (N.isEmpty(a)) { return EMPTY_STRING; } return join(a, 0, a.length, delimiter); } /** * Joins the elements of the provided array into a single String. * * @param a * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix * @param suffix * @return * @see #join(Object[], String, String, String, boolean) */ public static String join(final Object[] a, final String delimiter, final String prefix, final String suffix) { return join(a, 0, N.len(a), delimiter, prefix, suffix, false); } /** * Joins the elements of the provided array into a single String. * * @param a The array containing the elements to join together. It can be {@code null}. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. */ public static String join(final Object[] a, final String delimiter, final String prefix, final String suffix, final boolean trim) { return join(a, 0, N.len(a), delimiter, prefix, suffix, trim); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @see #join(Object[], int, int, String, String, String, boolean) */ public static String join(final Object[] a, final int fromIndex, final int toIndex, final char delimiter) { return join(a, fromIndex, toIndex, delimiter, false); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(Object[], int, int, String, String, String, boolean) */ public static String join(final Object[] a, final int fromIndex, final int toIndex, final char delimiter, final boolean trim) throws IndexOutOfBoundsException { // N.checkFromToIndex(fromIndex, toIndex, N.len(a)); // // if (N.isEmpty(a) || fromIndex == toIndex) { // return EMPTY_STRING; // } else if (toIndex - fromIndex == 1) { // return toString(a[fromIndex], trim); // } // // final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 16)); // // try { // for (int i = fromIndex; i < toIndex; i++) { // if (i > fromIndex) { // sb.append(delimiter); // } // // sb.append(toString(a[i], trim)); // } // // return sb.toString(); // } finally { // Objectory.recycle(sb); // } return join(a, fromIndex, toIndex, N.stringOf(delimiter), trim); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @see #join(Object[], int, int, String, String, String, boolean) */ public static String join(final Object[] a, final int fromIndex, final int toIndex, final String delimiter) { return join(a, fromIndex, toIndex, delimiter, false); } /** * Joins the elements of the provided array into a single String. * * @param a * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty, or {@code fromIndex == toIndex}. * @see #join(Object[], int, int, String, String, String, boolean) */ public static String join(final Object[] a, final int fromIndex, final int toIndex, final String delimiter, final boolean trim) { return join(a, fromIndex, toIndex, delimiter, null, null, trim); } /** * Joins the elements of the provided array into a single String. * The elements are selected from the specified range of the array. * * @param a The array containing the elements to join together. It can be {@code null}. * @param fromIndex The start index in the array from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the array up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the array size. */ public static String join(final Object[] a, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix, final boolean trim) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isEmpty(a) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } else if (toIndex - fromIndex == 1 && isEmpty(prefix) && isEmpty(suffix)) { return toString(a[fromIndex], trim); } // final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 16 + N.len(delimiter), N.len(prefix), N.len(suffix))); // // try { // if (isNotEmpty(prefix)) { // sb.append(prefix); // } // // if (isEmpty(delimiter)) { // for (int i = fromIndex; i < toIndex; i++) { // sb.append(toString(a[i], trim)); // } // } else { // for (int i = fromIndex; i < toIndex; i++) { // if (i > fromIndex) { // sb.append(delimiter); // } // // sb.append(toString(a[i], trim)); // } // } // // if (isNotEmpty(suffix)) { // sb.append(suffix); // } // // return sb.toString(); // } finally { // Objectory.recycle(sb); // } final int len = toIndex - fromIndex; final String[] elements = new String[len]; for (int i = fromIndex, j = 0; i < toIndex; i++, j++) { elements[j] = toString(a[i], trim); } elements[0] = concat(prefix, elements[0]); elements[len - 1] = concat(elements[len - 1], suffix); return String.join(nullToEmpty(delimiter), elements); } /** * Joins the elements of the provided Iterable into a single String. * * @param c * @return The concatenated string. Returns an empty string if the specified Iterable is {@code null} or empty * @see #join(Iterable, String, String, String, boolean) */ public static String join(final Iterable c) { return join(c, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided Iterable into a single String. * * @param c * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified Iterable is {@code null} or empty * @see #join(Iterable, String, String, String, boolean) */ public static String join(final Iterable c, final char delimiter) { return join(c == null ? null : c.iterator(), delimiter); } /** * Joins the elements of the provided Iterable into a single String. * * @param c * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified Iterable is {@code null} or empty * @see #join(Iterable, String, String, String, boolean) */ public static String join(final Iterable c, final String delimiter) { return join(c == null ? null : c.iterator(), delimiter); } /** * Joins the elements of the provided Iterable into a single String. * * @param c * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix * @param suffix * @return The concatenated string. Returns an empty string if the specified Iterable is {@code null} or empty and prefix, suffix are empty. * @see #join(Iterable, String, String, String, boolean) */ public static String join(final Iterable c, final String delimiter, final String prefix, final String suffix) { return join(c == null ? null : c.iterator(), delimiter, prefix, suffix); } /** * Joins the elements of the provided Iterable into a single String. * * @param c The Iterable containing the elements to join together. It can be {@code null}. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified Iterable is {@code null} or empty and prefix, suffix are empty. */ public static String join(final Iterable c, final String delimiter, final String prefix, final String suffix, final boolean trim) { if (c instanceof final Collection coll) { // NOSONAR return join(coll, 0, coll.size(), delimiter, prefix, suffix, trim); } else { return join(c == null ? null : c.iterator(), delimiter, prefix, suffix, trim); } } /** * Joins the elements of the provided Collection into a single String. * * @param c * @param fromIndex * @param toIndex * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified Collection is {@code null} or empty, or {@code fromIndex == toIndex}. * @see #join(Collection, int, int, String, String, String, boolean) */ public static String join(final Collection c, final int fromIndex, final int toIndex, final char delimiter) { return join(c, fromIndex, toIndex, delimiter, false); } /** * Joins the elements of the provided Collection into a single String. * * @param c * @param fromIndex * @param toIndex * @param delimiter The delimiter that separates each element. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified Collection is {@code null} or empty, or {@code fromIndex == toIndex}. * @throws IndexOutOfBoundsException * @see #join(Collection, int, int, String, String, String, boolean) */ public static String join(final Collection c, final int fromIndex, final int toIndex, final char delimiter, final boolean trim) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.size(c)); if (N.isEmpty(c) || fromIndex == toIndex) { return EMPTY_STRING; } // final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 16)); // // try { // int i = 0; // for (final Object e : c) { // if (i++ > fromIndex) { // sb.append(delimiter); // } // // if (i > fromIndex) { // sb.append(toString(e, trim)); // } // // if (i >= toIndex) { // break; // } // } // // return sb.toString(); // } finally { // Objectory.recycle(sb); // } return join(c, fromIndex, toIndex, N.stringOf(delimiter), trim); } /** * Joins the elements of the provided Collection into a single String. * * @param c * @param fromIndex * @param toIndex * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified Collection is {@code null} or empty, or {@code fromIndex == toIndex}. * @see #join(Collection, int, int, String, String, String, boolean) */ public static String join(final Collection c, final int fromIndex, final int toIndex, final String delimiter) { return join(c, fromIndex, toIndex, delimiter, false); } /** * Joins the elements of the provided Collection into a single String. * * @param c * @param fromIndex * @param toIndex * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified Collection is {@code null} or empty, or {@code fromIndex == toIndex}. * @see #join(Collection, int, int, String, String, String, boolean) */ public static String join(final Collection c, final int fromIndex, final int toIndex, final String delimiter, final boolean trim) { return join(c, fromIndex, toIndex, delimiter, null, null, trim); } /** * Joins the elements of the provided Collection into a single String. * The elements are selected from the specified range of the Collection. * * @param c The Collection containing the elements to join together. It can be {@code null}. * @param fromIndex The start index in the Collection from which to start joining elements. It must be a non-negative integer. * @param toIndex The end index in the Collection up to which to join elements. It must be a non-negative integer and not less than fromIndex. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified array is {@code null} or empty or {@code fromIndex == toIndex} and prefix, suffix are empty. * @throws IndexOutOfBoundsException if the fromIndex or toIndex is out of the range of the Collection size. */ public static String join(final Collection c, final int fromIndex, final int toIndex, final String delimiter, final String prefix, final String suffix, final boolean trim) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.size(c)); if (N.isEmpty(c) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } // final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 16 + N.len(delimiter), N.len(prefix), N.len(suffix))); // // try { // if (isNotEmpty(prefix)) { // sb.append(prefix); // } // // if (c instanceof List && c instanceof RandomAccess) { // final List list = (List) c; // // if (isEmpty(delimiter)) { // for (int i = fromIndex; i < toIndex; i++) { // sb.append(toString(list.get(i), trim)); // } // } else { // for (int i = fromIndex; i < toIndex; i++) { // if (i > fromIndex) { // sb.append(delimiter); // } // // sb.append(toString(list.get(i), trim)); // } // } // } else { // int i = 0; // if (isEmpty(delimiter)) { // for (final Object e : c) { // if (i++ >= fromIndex) { // sb.append(toString(e, trim)); // } // // if (i >= toIndex) { // break; // } // } // } else { // for (final Object e : c) { // if (i++ > fromIndex) { // sb.append(delimiter); // } // // if (i > fromIndex) { // sb.append(toString(e, trim)); // } // // if (i >= toIndex) { // break; // } // } // } // } // // if (isNotEmpty(suffix)) { // sb.append(suffix); // } // // return sb.toString(); // } finally { // Objectory.recycle(sb); // } final int len = toIndex - fromIndex; final String[] elements = new String[len]; if (c instanceof final List list && c instanceof RandomAccess) { for (int i = fromIndex, j = 0; i < toIndex; i++, j++) { elements[j] = toString(list.get(i), trim); } } else { int i = 0, j = 0; for (final Object e : c) { if (i++ >= fromIndex) { elements[j++] = toString(e, trim); } if (i >= toIndex) { break; } } } elements[0] = concat(prefix, elements[0]); elements[len - 1] = concat(elements[len - 1], suffix); return String.join(nullToEmpty(delimiter), elements); } /** * Joins the elements of the provided Iterator into a single String. * * @param iter * @return The concatenated string. Returns an empty string if the specified Iterator is {@code null} or empty * @see #join(Iterator, String, String, String, boolean) */ public static String join(final Iterator iter) { return join(iter, Strings.ELEMENT_SEPARATOR); } /** * Joins the elements of the provided Iterator into a single String. * * @param iter * @param delimiter The delimiter that separates each element. * @return The concatenated string. Returns an empty string if the specified Iterator is {@code null} or empty * @see #join(Iterator, String, String, String, boolean) */ public static String join(final Iterator iter, final char delimiter) { if (iter == null) { return EMPTY_STRING; } // final StringBuilder sb = Objectory.createStringBuilder(); // // try { // if (iter.hasNext()) { // sb.append(N.toString(iter.next())); // } // // while (iter.hasNext()) { // sb.append(delimiter); // // sb.append(N.toString(iter.next())); // } // // return sb.toString(); // } finally { // Objectory.recycle(sb); // } return join(iter, N.stringOf(delimiter)); } /** * Joins the elements of the provided Iterator into a single String. * * @param iter * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @return The concatenated string. Returns an empty string if the specified Iterator is {@code null} or empty * @see #join(Iterator, String, String, String, boolean) */ public static String join(final Iterator iter, final String delimiter) { return join(iter, delimiter, EMPTY_STRING, EMPTY_STRING, false); } /** * Joins the elements of the provided Iterator into a single String. * * @param iter The Iterator containing the elements to join together. It can be {@code null}. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @return The concatenated string. Returns an empty string if the specified Iterator is {@code null} or empty and prefix, suffix are empty. * @see #join(Iterator, String, String, String, boolean) */ public static String join(final Iterator iter, final String delimiter, final String prefix, final String suffix) { return join(iter, delimiter, prefix, suffix, false); } /** * Joins the elements of the provided Iterator into a single String. * * @param iter The Iterator containing the elements to join together. It can be {@code null}. * @param delimiter The delimiter that separates each element. It can be empty, in which case the elements are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if the specified Iterator is {@code null} or empty and prefix, suffix are empty. */ public static String join(final Iterator iter, final String delimiter, final String prefix, final String suffix, final boolean trim) { if (iter == null) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } // final StringBuilder sb = Objectory.createStringBuilder(); // // try { // if (isNotEmpty(prefix)) { // sb.append(prefix); // } // // if (isEmpty(delimiter)) { // while (iter.hasNext()) { // if (trim) { // sb.append(N.toString(iter.next()).trim()); // } else { // sb.append(N.toString(iter.next())); // } // } // } else { // if (iter.hasNext()) { // sb.append(N.toString(iter.next())); // } // // while (iter.hasNext()) { // sb.append(delimiter); // // if (trim) { // sb.append(N.toString(iter.next()).trim()); // } else { // sb.append(N.toString(iter.next())); // } // } // } // // if (isNotEmpty(suffix)) { // sb.append(suffix); // } // // return sb.toString(); // } finally { // Objectory.recycle(sb); // } final List list = N.toList(iter); return join(list, 0, list.size(), delimiter, prefix, suffix, trim); } /** * Joins the entries of the provided Map into a single String. * * @param m * @return * @see #joinEntries(Map, String, String, String, String, boolean) */ public static String joinEntries(final Map m) { return joinEntries(m, Strings.ELEMENT_SEPARATOR); } /** * Joins the entries of the provided Map into a single String. * * @param m * @param entryDelimiter The delimiter that separates each entry * @return * @see #joinEntries(Map, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final char entryDelimiter) { if (N.isEmpty(m)) { return EMPTY_STRING; } return joinEntries(m, 0, m.size(), entryDelimiter); } /** * Joins the entries of the provided Map into a single String. * * @param m * @param entryDelimiter The delimiter that separates each entry * @return * @see #joinEntries(Map, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final String entryDelimiter) { if (N.isEmpty(m)) { return EMPTY_STRING; } return joinEntries(m, 0, m.size(), entryDelimiter); } /** * Joins the entries of the provided Map into a single String. * * @param m * @param entryDelimiter The delimiter that separates each entry * @param keyValueDelimiter * @return * @see #joinEntries(Map, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final char entryDelimiter, final char keyValueDelimiter) { if (N.isEmpty(m)) { return EMPTY_STRING; } return joinEntries(m, 0, m.size(), entryDelimiter, keyValueDelimiter); } /** * Joins the entries of the provided Map into a single String. * * @param m * @param keyValueDelimiter The delimiter that separates the key and value within each entry. It can be empty, in which case the key and value are concatenated without any delimiter. * @param keyValueDelimiter * @return * @see #joinEntries(Map, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final String entryDelimiter, final String keyValueDelimiter) { if (N.isEmpty(m)) { return EMPTY_STRING; } return joinEntries(m, 0, m.size(), entryDelimiter, keyValueDelimiter); } /** * Joins the entries of the provided Map into a single String. * * @param m * @param keyValueDelimiter The delimiter that separates the key and value within each entry. It can be empty, in which case the key and value are concatenated without any delimiter. * @param keyValueDelimiter * @param prefix * @param suffix * @return * @see #joinEntries(Map, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final String entryDelimiter, final String keyValueDelimiter, final String prefix, final String suffix) { return joinEntries(m, 0, N.size(m), entryDelimiter, keyValueDelimiter, prefix, suffix, false); } /** * Joins the entries of the provided Map into a single String. * The entryDelimiter separates each entry and keyValueDelimiter separates the key and value within each entry. * The prefix and suffix are added to each entry before joining. * * @param m The Map containing the entries to join together. It can be empty. * @param entryDelimiter The delimiter that separates each entry. It can be empty, in which case the entries are concatenated without any delimiter. * @param keyValueDelimiter The delimiter that separates the key and value within each entry. It can be empty, in which case the key and value are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, trims the string representations of each element. * @return The concatenated string. Returns an empty string if 'm' is {@code null} or empty and prefix'/'suffix are empty. */ public static String joinEntries(final Map m, final String entryDelimiter, final String keyValueDelimiter, final String prefix, final String suffix, final boolean trim) { return joinEntries(m, 0, N.size(m), entryDelimiter, keyValueDelimiter, prefix, suffix, trim); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * Each entry is represented as "key + keyValueDelimiter + value". * The entries are joined with the specified entryDelimiter. * If the trim flag is set to {@code true}, the leading and trailing whitespace of each entry will be removed. * The keys and values are transformed using the provided keyExtractor and valueExtractor functions respectively. * * @param m The Map containing the entries to join together. It can be empty. * @param entryDelimiter The delimiter that separates each entry. It can be empty, in which case the entries are concatenated without any delimiter. * @param keyValueDelimiter The delimiter that separates the key and value within each entry. It can be empty, in which case the key and value are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, leading and trailing whitespace of each entry will be removed. * @param keyExtractor The function to be used to transform the keys. It should not be {@code null}. * @param valueExtractor The function to be used to transform the values. It should not be {@code null}. * @return The concatenated string. Returns an empty string if 'm' is {@code null} or empty and prefix'/'suffix are empty. * @throws IllegalArgumentException if the map is {@code null}, either delimiter is {@code null}, or the mapper functions are {@code null}. */ public static String joinEntries(final Map m, final String entryDelimiter, final String keyValueDelimiter, final String prefix, final String suffix, final boolean trim, final Function keyExtractor, final Function valueExtractor) throws IllegalArgumentException { N.checkArgNotNull(keyExtractor, cs.keyExtractor); N.checkArgNotNull(valueExtractor, cs.valueExtractor); if (N.isEmpty(m)) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } final StringBuilder sb = Objectory .createStringBuilder(calculateBufferSize(m.size(), 32 + N.len(entryDelimiter) + N.len(keyValueDelimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } int i = 0; for (final Map.Entry entry : m.entrySet()) { if (i++ > 0) { sb.append(entryDelimiter); } if (trim) { sb.append(N.toString(keyExtractor.apply(entry.getKey())).trim()); sb.append(keyValueDelimiter); sb.append(N.toString(valueExtractor.apply(entry.getValue())).trim()); } else { sb.append(N.toString(keyExtractor.apply(entry.getKey()))); sb.append(keyValueDelimiter); sb.append(N.toString(valueExtractor.apply(entry.getValue()))); } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param entryDelimiter The delimiter that separates each entry * @return * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final char entryDelimiter) { return joinEntries(m, fromIndex, toIndex, entryDelimiter, false); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param entryDelimiter The delimiter that separates each entry * @param trim * @return * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final char entryDelimiter, final boolean trim) { return joinEntries(m, fromIndex, toIndex, entryDelimiter, WD._EQUAL, trim); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param entryDelimiter The delimiter that separates each entry * @return * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final String entryDelimiter) { return joinEntries(m, fromIndex, toIndex, entryDelimiter, false); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param entryDelimiter The delimiter that separates each entry * @param trim * @return * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final String entryDelimiter, final boolean trim) { return joinEntries(m, fromIndex, toIndex, entryDelimiter, WD.EQUAL, null, null, trim); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param entryDelimiter The delimiter that separates each entry * @param keyValueDelimiter * @return * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final char entryDelimiter, final char keyValueDelimiter) { return joinEntries(m, fromIndex, toIndex, entryDelimiter, keyValueDelimiter, false); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param entryDelimiter The delimiter that separates each entry * @param keyValueDelimiter * @param trim * @return * @throws IndexOutOfBoundsException * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final char entryDelimiter, final char keyValueDelimiter, final boolean trim) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.size(m)); if (N.isEmpty(m) || fromIndex == toIndex) { return EMPTY_STRING; } final StringBuilder sb = Objectory.createStringBuilder(calculateBufferSize(toIndex - fromIndex, 32)); try { int i = 0; for (final Map.Entry entry : m.entrySet()) { if (i++ > fromIndex) { sb.append(entryDelimiter); } if (i > fromIndex) { sb.append(toString(entry.getKey(), trim)); sb.append(keyValueDelimiter); sb.append(toString(entry.getValue(), trim)); } if (i >= toIndex) { break; } } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Joins the entries of the provided map into a string, using the specified delimiters. * * @param m * @param fromIndex * @param toIndex * @param keyValueDelimiter The delimiter that separates the key and value within each entry. It can be empty, in which case the key and value are concatenated without any delimiter. * @param keyValueDelimiter * @return * @see #joinEntries(Map, int, int, String, String, String, String, boolean) */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final String entryDelimiter, final String keyValueDelimiter) { return joinEntries(m, fromIndex, toIndex, entryDelimiter, keyValueDelimiter, null, null, false); } /** * Joins the entries of the provided map into a string, using the specified delimiters. * The entries are taken from the specified range of the map's entry set (fromIndex, inclusive, to toIndex, exclusive). * Each entry is represented as "key + keyValueDelimiter + value". * The entries are joined with the specified entryDelimiter. * If the trim flag is set to {@code true}, the leading and trailing whitespace of each entry will be removed. * * @param m The Map containing the entries to join together. It can be empty. * @param fromIndex The start index in the entry set from which to start joining entries. It should be non-negative and no larger than the size of the map. * @param toIndex The end index in the entry set up to which to join entries. It should be non-negative, no larger than the size of the map, and not less than fromIndex. * @param entryDelimiter The delimiter that separates each entry. It can be empty, in which case the entries are concatenated without any delimiter. * @param keyValueDelimiter The delimiter that separates the key and value within each entry. It can be empty, in which case the key and value are concatenated without any delimiter. * @param prefix The prefix to be added at the beginning. It can be empty. * @param suffix The suffix to be added at the end. It can be empty. * @param trim If {@code true}, leading and trailing whitespace of each entry will be removed. * @return The concatenated string. Returns an empty string if 'm' is {@code null} or empty and prefix'/'suffix are empty. * @throws IndexOutOfBoundsException if fromIndex or toIndex is out of range. */ public static String joinEntries(final Map m, final int fromIndex, final int toIndex, final String entryDelimiter, final String keyValueDelimiter, final String prefix, final String suffix, final boolean trim) throws IndexOutOfBoundsException { N.checkFromToIndex(fromIndex, toIndex, N.size(m)); if (N.isEmpty(m) || fromIndex == toIndex) { if (isEmpty(prefix) && isEmpty(suffix)) { return EMPTY_STRING; } else if (isEmpty(prefix)) { return suffix; } else if (isEmpty(suffix)) { return prefix; } else { return concat(prefix, suffix); } } final StringBuilder sb = Objectory.createStringBuilder( calculateBufferSize(toIndex - fromIndex, 32 + N.len(entryDelimiter) + N.len(keyValueDelimiter), N.len(prefix), N.len(suffix))); try { if (isNotEmpty(prefix)) { sb.append(prefix); } int i = 0; for (final Map.Entry entry : m.entrySet()) { if (i++ > fromIndex) { sb.append(entryDelimiter); } if (i > fromIndex) { if (trim) { sb.append(N.toString(entry.getKey()).trim()); sb.append(keyValueDelimiter); sb.append(N.toString(entry.getValue()).trim()); } else { sb.append(N.toString(entry.getKey())); sb.append(keyValueDelimiter); sb.append(N.toString(entry.getValue())); } } if (i >= toIndex) { break; } } if (isNotEmpty(suffix)) { sb.append(suffix); } return sb.toString(); } finally { Objectory.recycle(sb); } } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @return */ public static String concat(final String a, final String b) { if (N.isEmpty(a)) { return N.isEmpty(b) ? Strings.EMPTY_STRING : b; } else { return N.isEmpty(b) ? a : a.concat(b); } } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @return */ public static String concat(final String a, final String b, final String c) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @param d * @return */ public static String concat(final String a, final String b, final String c, final String d) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c), nullToEmpty(d)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @return */ public static String concat(final String a, final String b, final String c, final String d, final String e) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c), nullToEmpty(d), nullToEmpty(e)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @return */ public static String concat(final String a, final String b, final String c, final String d, final String e, final String f) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c), nullToEmpty(d), nullToEmpty(e), nullToEmpty(f)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @param g * @return */ public static String concat(final String a, final String b, final String c, final String d, final String e, final String f, final String g) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c), nullToEmpty(d), nullToEmpty(e), nullToEmpty(f), nullToEmpty(g)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @param g * @param h * @return */ public static String concat(final String a, final String b, final String c, final String d, final String e, final String f, final String g, final String h) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c), nullToEmpty(d), nullToEmpty(e), nullToEmpty(f), nullToEmpty(g), nullToEmpty(h)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @param g * @param h * @param i * @return The concatenated string. Returns {@code ""} if all input Strings are {@code null} or empty.. */ public static String concat(final String a, final String b, final String c, final String d, final String e, final String f, final String g, final String h, final String i) { return String.join(Strings.EMPTY_STRING, nullToEmpty(a), nullToEmpty(b), nullToEmpty(c), nullToEmpty(d), nullToEmpty(e), nullToEmpty(f), nullToEmpty(g), nullToEmpty(h), nullToEmpty(i)); } /** * Concatenates the given strings into a single string. * {@code Null} strings are converted to empty strings before concatenation. * * @param a * @return */ @SafeVarargs public static String concat(final String... a) { final int len = N.len(a); switch (len) { case 0: return EMPTY_STRING; case 1: return nullToEmpty(a[0]); case 2: return concat(a[0], a[1]); case 3: return concat(a[0], a[1], a[2]); case 4: return concat(a[0], a[1], a[2], a[3]); case 5: return concat(a[0], a[1], a[2], a[3], a[4]); case 6: return concat(a[0], a[1], a[2], a[3], a[4], a[5]); case 7: return concat(a[0], a[1], a[2], a[3], a[4], a[5], a[6]); default: { final String[] b = N.copyThenReplaceAll(a, Fn.nullToEmpty()); return String.join(Strings.EMPTY_STRING, b); } } } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @return */ public static String concat(final Object a, final Object b) { return Strings.concat(N.toString(a), N.toString(b)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @param c * @return * @see #concat(Object, Object) */ public static String concat(final Object a, final Object b, final Object c) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @param c * @param d * @return * @see #concat(Object, Object) */ public static String concat(final Object a, final Object b, final Object c, final Object d) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @return * @see #concat(Object, Object) */ public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @return * @see #concat(Object, Object) */ public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @param g * @return * @see #concat(Object, Object) */ public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f, final Object g) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f), N.toString(g)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a * @param b * @param c * @param d * @param e * @param f * @param g * @param h * @return * @see #concat(Object, Object) */ public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f, final Object g, final Object h) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f), N.toString(g), N.toString(h)); } /** * Concatenates the string representations of the provided objects into a single string. * {@code Null} objects are converted to empty "" strings before concatenation. * * @param a The first object to concatenate. It can be {@code null}. * @param b The second object to concatenate. It can be {@code null}. * @param c The third object to concatenate. It can be {@code null}. * @param d The fourth object to concatenate. It can be {@code null}. * @param e The fifth object to concatenate. It can be {@code null}. * @param f The sixth object to concatenate. It can be {@code null}. * @param g The seventh object to concatenate. It can be {@code null}. * @param h The eighth object to concatenate. It can be {@code null}. * @return The concatenated string. Returns {@code ""} if all input objects are {@code null} or empty. */ public static String concat(final Object a, final Object b, final Object c, final Object d, final Object e, final Object f, final Object g, final Object h, final Object i) { return Strings.concat(N.toString(a), N.toString(b), N.toString(c), N.toString(d), N.toString(e), N.toString(f), N.toString(g), N.toString(h), N.toString(i)); } // /** // * // * @param a // * @return // * @see #concat(Object, Object) // * @deprecated // */ // @Deprecated // @SafeVarargs // public static String concat(final Object... a) { // if (N.isEmpty(a)) { // return EMPTY_STRING; // } else if (a.getClass().equals(String[].class)) { // return Strings.concat((String[]) a); // } // // final StringBuilder sb = ObjectFactory.createStringBuilder(); // // try { // for (Object e : a) { // sb.append(N.toString(e)); // } // return sb.toString(); // } finally { // ObjectFactory.recycle(sb); // } // } // // /** // * // * @param c // * @return // * @deprecated // */ // @Deprecated // public static String concat(final Collection c) { // if (N.isEmpty(c)) { // return EMPTY_STRING; // } // // final StringBuilder sb = ObjectFactory.createStringBuilder(); // // try { // for (Object e : c) { // sb.append(N.toString(e)); // } // return sb.toString(); // } finally { // ObjectFactory.recycle(sb); // } // } private static String toString(final Object e, final boolean trim) { if (e == null) { return NULL_STRING; } if (trim) { return N.toString(e).trim(); } else { return N.toString(e); } } /** * Copied from Google Guava * *
    * * Returns the given {@code template} string with each occurrence of {@code "%s"} replaced by * the corresponding argument value from {@code args}; or, if the placeholder and argument counts * do not match, returns a best-effort form of that string. Will not throw an exception under * normal conditions. * *

    Note: For most string-formatting needs, use {@link String#format String.format}, * {@link java.io.PrintWriter#format PrintWriter.format}, and related methods. These support the * full range of format * specifiers, and alert you to usage errors by throwing {@link * java.util.IllegalFormatException}. * *

    In certain cases, such as outputting debugging information or constructing a message to be * used for another unchecked exception, an exception during string formatting would serve little * purpose except to supplant the real information you were trying to provide. These are the cases * this method is made for; it instead generates a best-effort string with all supplied argument * values present. This method is also useful in environments such as GWT where {@code * String.format} is not available. As an example, method implementations of the {@code Preconditions} class use this formatter, for both of the reasons just discussed. * *

    Warning: Only the exact two-character placeholder sequence {@code "%s"} is * recognized. * * @param template a string containing zero or more {@code "%s"} placeholder sequences. {@code * null} is treated as the four-character string {@code "null"}. * @param args the arguments to be substituted into the message template. The first argument * specified is substituted for the first occurrence of {@code "%s"} in the template, and so * forth. A {@code null} argument is converted to the four-character string {@code "null"}; * {@code non-null} values are converted to strings using {@link Object#toString()}. * @return */ // TODO(diamondm) consider using Arrays.toString() for array parameters public static String lenientFormat(String template, Object... args) { template = String.valueOf(template); // null -> "null" if (args == null) { args = new Object[] { "(Object[])null" }; } else { for (int i = 0; i < args.length; i++) { args[i] = lenientToString(args[i]); } } // start substituting the arguments into the '%s' placeholders final StringBuilder sb = Objectory.createStringBuilder(template.length() + 16 * args.length); int templateStart = 0; int i = 0; while (i < args.length) { final int placeholderStart = template.indexOf("%s", templateStart); if (placeholderStart == -1) { break; } sb.append(template, templateStart, placeholderStart); sb.append(args[i++]); templateStart = placeholderStart + 2; } sb.append(template, templateStart, template.length()); // if we run out of placeholders, append the extra args in square braces if (i < args.length) { sb.append(" ["); sb.append(args[i++]); while (i < args.length) { sb.append(", "); sb.append(args[i++]); } sb.append(']'); } final String result = sb.toString(); Objectory.recycle(sb); return result; } /** * Lenient to string. * * @param obj * @return */ private static String lenientToString(final Object obj) { try { return String.valueOf(obj); } catch (final Exception e) { // Default toString() behavior - see Object.toString() final String objectToString = obj.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(obj)); // Logger is created inline with fixed name to avoid forcing Proguard to create another class. // Logger.getLogger("com.google.common.base.Strings").log(WARNING, "Exception during lenientFormat for " + objectToString, e); LOGGER.warn("Exception during lenientFormat for " + objectToString, e); //NOSONAR return "<" + objectToString + " threw " + e.getClass().getName() + ">"; } } /** * Reverses the characters in the given string. * * @param str The string to be reversed. May be {@code null} or empty. * @return A new string with the characters reversed. If the input string is {@code null} or empty or its length <= 1, the input string is returned. */ public static String reverse(final String str) { if (N.len(str) <= 1) { return str; } final StringBuilder sb = Objectory.createStringBuilder(str.length()); try { sb.append(str); return sb.reverse().toString(); } finally { Objectory.recycle(sb); } } /** *

    * Reverses a String that is delimited by a specific character. *

    * *

    * The Strings between the delimiters are not reversed. Thus * java.lang.String becomes String.lang.java (if the delimiter is * {@code '.'}). *

    * *
         * Strings.reverseDelimited(null, *)      = null
         * Strings.reverseDelimited("", *)        = ""
         * Strings.reverseDelimited("a.b.c", 'x') = "a.b.c"
         * Strings.reverseDelimited("a.b.c", ".") = "c.b.a"
         * 
    * * @param str * the String to reverse, may be null * @param delimiter * the delimiter character to use * @return the specified String if it's {@code null} or empty. If the input string is {@code null} or empty or its length <= 1, the input string is returned. */ public static String reverseDelimited(final String str, final char delimiter) { if (N.len(str) <= 1) { return str; } // could implement manually, but simple way is to reuse other, // probably slower, methods. final String[] strs = split(str, delimiter); N.reverse(strs); return join(strs, delimiter); } /** * Reverses the order of delimited elements in a string. * * @param str The string to be reversed. May be {@code null} or empty. * @param delimiter The delimiter that separates the elements in the string. * @return The reversed string. If the input string is {@code null} or empty or its length <= 1, the input string is returned. */ public static String reverseDelimited(final String str, final String delimiter) { if (N.len(str) <= 1) { return str; } // could implement manually, but simple way is to reuse other, // probably slower, methods. final String[] strs = split(str, delimiter); N.reverse(strs); return join(strs, delimiter); } /** * Returns a new sorted String if the specified {@code str} is not {@code null} or empty, otherwise the specified {@code str} is returned. * * @param str * @return the specified String if it's {@code null} or empty. If the input string is {@code null} or empty or its length <= 1, the input string is returned. */ public static String sort(final String str) { if (N.len(str) <= 1) { return str; } final char[] chs = str.toCharArray(); N.sort(chs); return String.valueOf(chs); } // Rotating (circular shift) //----------------------------------------------------------------------- /** *

    Rotate (circular shift) a String of {@code shift} characters.

    *
      *
    • If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)
    • *
    • If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)
    • *
    * *
         * Strings.rotate(null, *)        = null
         * Strings.rotate("", *)          = ""
         * Strings.rotate("abcdefg", 0)   = "abcdefg"
         * Strings.rotate("abcdefg", 2)   = "fgabcde"
         * Strings.rotate("abcdefg", -2)  = "cdefgab"
         * Strings.rotate("abcdefg", 7)   = "abcdefg"
         * Strings.rotate("abcdefg", -7)  = "abcdefg"
         * Strings.rotate("abcdefg", 9)   = "fgabcde"
         * Strings.rotate("abcdefg", -9)  = "cdefgab"
         * 
    * * @param str the String to rotate, may be null * @param shift number of time to shift (positive : right shift, negative : left shift) * @return the rotated String, * or the original String if {@code shift == 0}, * or {@code null} if {@code null} String input */ public static String rotate(final String str, final int shift) { final int strLen = N.len(str); if (strLen <= 1 || shift == 0 || shift % strLen == 0) { return str; } int offset = -(shift % strLen); if (offset < 0) { offset = str.length() + offset; } if (offset < 0) { offset = 0; } return substring(str, offset) + Strings.substring(str, 0, offset); } /** * Shuffles the characters in the given string. * * @param str The string to be shuffled. May be {@code null} or empty. * @return A new string with the characters shuffled. If the input string is {@code null} or empty, the input string is returned. */ public static String shuffle(final String str) { return shuffle(str, N.RAND); } /** * Shuffles the characters in the given string using the provided Random instance. * * @param str The string to be shuffled. May be {@code null} or empty. * @param rnd The Random instance used to shuffle the characters. * @return A new string with the characters shuffled. If the input string is {@code null} or empty, the input string is returned. */ public static String shuffle(final String str, final Random rnd) { final int strLen = N.len(str); if (strLen <= 1) { return str; } final char[] chars = str.toCharArray(); N.shuffle(chars, rnd); return String.valueOf(chars); } // Overlay //----------------------------------------------------------------------- /** *

    Overlays part of a String with another String.

    * *
         * Strings.overlay(null, "abc", 0, 0)          = "abc"
         * Strings.overlay("", "abc", 0, 0)          = "abc"
         * Strings.overlay("abcdef", {@code null}, 2, 4)     = "abef"
         * Strings.overlay("abcdef", "", 2, 4)       = "abef"
         * Strings.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
         * 
    * * @param str the String to do overlaying in, may be null * @param overlay the String to overlay, may be null * @param start the position to start overlaying at * @param end the position to stop overlaying before * @return overlayed String, {@code ""} if {@code null} String input * @throws IndexOutOfBoundsException * @see #replace(String, int, int, String) * @see N#replaceRange(String, int, int, String) * @deprecated replaced by {@code replace(String, int, int, String)} */ @Deprecated public static String overlay(final String str, final String overlay, final int start, final int end) throws IndexOutOfBoundsException { return replace(str, start, end, overlay); } /** * Parses the string argument as a boolean. * The boolean returned represents a {@code true} value if the string argument is not {@code null} and is equal, ignoring case, to the string "true". * * @param str The string to be parsed. May be {@code null}. * @return The boolean represented by the string argument. * @see Boolean#parseBoolean(String) */ public static boolean parseBoolean(final String str) { return !Strings.isEmpty(str) && Boolean.parseBoolean(str); } /** * Parses the string argument as a char. * If the specified String is {@code null} or empty, Returns the char represented by the string argument is {@code '\0'}. * Else if the length of the specified String is 1, it returns the char represented by the string argument. * Otherwise, it returns the char represented by the integer value of the string argument. * * @param str The string to be parsed. May be {@code null}. * @return The char represented by the string argument. */ public static char parseChar(final String str) { return Strings.isEmpty(str) ? CHAR_ZERO : ((str.length() == 1) ? str.charAt(0) : (char) Integer.parseInt(str)); } /** * Returns the value by calling {@code Byte.valueOf(String)} if {@code str} * is not {@code null}, otherwise, the default value 0 for {@code byte} is * returned. * * @param str * @return * @throws NumberFormatException If the string is not a parsable {@code byte}. * @see Numbers#toByte(String) * @deprecated replaced by {@code Numbers.toByte(String)} */ @Deprecated public static byte parseByte(final String str) throws NumberFormatException { return Numbers.toByte(str); } /** * Returns the value by calling {@code Short.valueOf(String)} if {@code str} * is not {@code null}, otherwise, the default value 0 for {@code short} is * returned. * * @param str * @return * @throws NumberFormatException If the string is not a parsable {@code short}. * @see Numbers#toShort(String) * @deprecated replaced by {@code Numbers.toShort(String)} */ @Deprecated public static short parseShort(final String str) throws NumberFormatException { return Numbers.toShort(str); } /** * Returns the value by calling {@code Integer.valueOf(String)} if * {@code str} is not {@code null}, otherwise, the default value 0 for * {@code int} is returned. * * @param str * @return * @throws NumberFormatException If the string is not a parsable {@code int}. * @see Numbers#toInt(String) * @deprecated replaced by {@code Numbers.toInt(String)} */ @Deprecated public static int parseInt(final String str) throws NumberFormatException { return Numbers.toInt(str); } /** * Returns the value by calling {@code Long.valueOf(String)} if {@code str} * is not {@code null}, otherwise, the default value 0 for {@code long} is * returned. * * @param str * @return * @throws NumberFormatException If the string is not a parsable {@code long}. * @see Numbers#toLong(String) * @deprecated replaced by {@code Numbers.toLong(String)} */ @Deprecated public static long parseLong(final String str) throws NumberFormatException { return Numbers.toLong(str); } /** * Returns the value by calling {@code Float.valueOf(String)} if {@code str} * is not {@code null}, otherwise, the default value 0f for {@code float} is * returned. * * @param str * @return * @throws NumberFormatException If the string is not a parsable {@code float}. * @see Numbers#toFloat(String) * @deprecated replaced by {@code Numbers.toFloat(String)} */ @Deprecated public static float parseFloat(final String str) throws NumberFormatException { return Numbers.toFloat(str); } /** * Returns the value by calling {@code Double.valueOf(String)} if {@code str} * is not {@code null}, otherwise, the default value 0d for {@code double} is * returned. * * @param str * @return * @throws NumberFormatException If the string is not a parsable {@code double}. * @see Numbers#toDouble(String) * @deprecated replaced by {@code Numbers.toDouble(String)} */ @Deprecated public static double parseDouble(final String str) throws NumberFormatException { return Numbers.toDouble(str); } /** * Encodes the given binary data into a Base64 encoded string. * * @param binaryData The byte array to be encoded. * @return The Base64 encoded string, or an empty String {@code ""} if the input byte array is {@code null} or empty. */ public static String base64Encode(final byte[] binaryData) { if (N.isEmpty(binaryData)) { return Strings.EMPTY_STRING; } return BASE64_ENCODER.encodeToString(binaryData); } /** * Encodes the given string into a Base64 encoded string. * * @param str The string to be encoded. * @return The Base64 encoded string, or an empty String {@code ""} if the input string is {@code null} or empty. */ public static String base64EncodeString(final String str) { if (Strings.isEmpty(str)) { return Strings.EMPTY_STRING; } return BASE64_ENCODER.encodeToString(str.getBytes()); // NOSONAR } /** * Encodes the given string into a Base64 encoded string using UTF-8 encoding. * * @param str The string to be encoded. * @return The Base64 encoded string, or an empty String {@code ""} if the input string is {@code null} or empty. * @see #base64EncodeString(String, Charset) */ public static String base64EncodeUtf8String(final String str) { return base64EncodeString(str, Charsets.UTF_8); } /** * Encodes the given string to a Base64 encoded string using the specified charset. * * @param str The string to be encoded. * @param charset The charset to be used to encode the input string. * @return The Base64 encoded string. * @see String#getBytes(Charset) */ public static String base64EncodeString(final String str, final Charset charset) { if (Strings.isEmpty(str)) { return Strings.EMPTY_STRING; } return BASE64_ENCODER.encodeToString(str.getBytes(charset)); // NOSONAR } /** * Decodes the given Base64 encoded string to a byte array. * * @param base64String The Base64 encoded string to be decoded. * @return The decoded byte array, or an empty byte array if the input string is {@code null} or empty. */ public static byte[] base64Decode(final String base64String) { if (Strings.isEmpty(base64String)) { return N.EMPTY_BYTE_ARRAY; } return BASE64_DECODER.decode(base64String); } /** * Decodes the given Base64 encoded string to its original string representation. * * @param base64String The Base64 encoded string to be decoded. * @return The decoded string, or an empty String {@code ""} if the input string is {@code null} or empty. */ public static String base64DecodeToString(final String base64String) { if (Strings.isEmpty(base64String)) { return Strings.EMPTY_STRING; } return new String(base64Decode(base64String)); // NOSONAR } /** * Decodes the given Base64 URL encoded string to a UTF-8 string. * * @param base64String The Base64 URL encoded string to be decoded. * @return The decoded UTF-8 string, or an empty String {@code ""} if the input string is {@code null} or empty. */ public static String base64DecodeToUtf8String(final String base64String) { return base64DecodeToString(base64String, Charsets.UTF_8); } /** * Decodes the given Base64 encoded string to a string using the specified charset. * * @param base64String The Base64 encoded string to be decoded. * @param charset The charset to be used to decode the resulting byte array. * @return The decoded string. * @see String#String(byte[], Charset) */ public static String base64DecodeToString(final String base64String, final Charset charset) { if (Strings.isEmpty(base64String)) { return Strings.EMPTY_STRING; } return new String(base64Decode(base64String), charset); // NOSONAR } /** * Encodes the given byte array to a Base64 URL encoded string. * * @param binaryData The byte array to be encoded. * @return The Base64 URL encoded string, or an empty String {@code ""} if the input byte array is {@code null} or empty. */ public static String base64UrlEncode(final byte[] binaryData) { if (N.isEmpty(binaryData)) { return Strings.EMPTY_STRING; } return BASE64_URL_ENCODER.encodeToString(binaryData); } /** * Decodes the given Base64 URL encoded string to a byte array. * * @param base64String The Base64 URL encoded string to be decoded. * @return The decoded byte array, an empty byte array if the input string is {@code null} or empty. */ public static byte[] base64UrlDecode(final String base64String) { if (Strings.isEmpty(base64String)) { return N.EMPTY_BYTE_ARRAY; } return BASE64_URL_DECODER.decode(base64String); } /** * Decodes the given Base64 URL encoded string to a regular string. * * @param base64String The Base64 URL encoded string to be decoded. * @return The decoded string, or an empty String {@code ""} if the input string is {@code null} or empty. */ public static String base64UrlDecodeToString(final String base64String) { if (Strings.isEmpty(base64String)) { return Strings.EMPTY_STRING; } return new String(BASE64_URL_DECODER.decode(base64String)); // NOSONAR } /** * Decodes the given Base64 URL encoded string to a UTF-8 string. * * @param base64String The Base64 URL encoded string to be decoded. * @return The decoded UTF-8 string, or an empty String {@code ""} if the input string is {@code null} or empty. */ public static String base64UrlDecodeToUtf8String(final String base64String) { return base64UrlDecodeToString(base64String, Charsets.UTF_8); } /** * Decodes the given Base64 URL encoded string to a string using the specified charset. * * @param base64String The Base64 URL encoded string to be decoded. * @param charset The charset to be used to decode the based decoded {@code bytes} * @return The decoded string, or an empty String {@code ""} if the input string is {@code null} or empty. */ public static String base64UrlDecodeToString(final String base64String, final Charset charset) { if (Strings.isEmpty(base64String)) { return Strings.EMPTY_STRING; } return new String(BASE64_URL_DECODER.decode(base64String), charset); } /** * Encodes the given parameters into a URL-encoded string. * * @param parameters The parameters to be URL-encoded. * @return The URL-encoded string representation of the parameters. * @see URLEncodedUtil#encode(Object) */ public static String urlEncode(final Object parameters) { return URLEncodedUtil.encode(parameters); } /** * Encodes the given parameters into a URL-encoded string using the specified charset. * * @param parameters The parameters to be URL-encoded. * @param charset The charset to be used for encoding. * @return The URL-encoded string representation of the parameters. * @see URLEncodedUtil#encode(Object, Charset) */ public static String urlEncode(final Object parameters, final Charset charset) { return URLEncodedUtil.encode(parameters, charset); } /** * Decodes the given URL query string into a map of key-value pairs. * * @param urlQuery The URL query string to be decoded. * @return A map containing the decoded key-value pairs from the URL query string. * @see URLEncodedUtil#decode(String) */ public static Map urlDecode(final String urlQuery) { return URLEncodedUtil.decode(urlQuery); } /** * Decodes the given URL query string into a map of key-value pairs using the specified charset. * * @param urlQuery The URL query string to be decoded. * @param charset The charset to be used for decoding. * @return A map containing the decoded key-value pairs from the URL query string. * @see URLEncodedUtil#decode(String, Charset) */ public static Map urlDecode(final String urlQuery, final Charset charset) { return URLEncodedUtil.decode(urlQuery, charset); } /** * Decodes the given URL query string into an object of the specified type. * * @param The type of the object to be returned. * @param urlQuery The URL query string to be decoded. * @param targetType The class of the object to be returned. * @return An object of the specified type containing the decoded data from the URL query string. * @see URLEncodedUtil#decode(String, Class) */ public static T urlDecode(final String urlQuery, final Class targetType) { return URLEncodedUtil.decode(urlQuery, targetType); } /** * Decodes a URL query string into an object of the specified type. * The query string is expected to be in application/x-www-form-urlencoded format. * * @param The type of the object to be returned. * @param urlQuery The URL query string to be decoded. * @param charset The charset to be used for decoding. * @param targetType The class of the object to be returned. * @return An object of type T that represents the decoded URL query string. * @see URLEncodedUtil#decode(String, Charset, Class) */ public static T urlDecode(final String urlQuery, final Charset charset, final Class targetType) { return URLEncodedUtil.decode(urlQuery, charset, targetType); } /** * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified * in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 * alphabet but fall within the bounds of the array are translated to -1. *

    * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit). *

    *

    * Thanks to "commons" project in ws.apache.org for this code. * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ *

    */ private static final byte[] DECODE_TABLE = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - / 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z }; /** * Byte used to pad output. */ protected static final byte PAD_DEFAULT = '='; // Allow static access to default /** * Returns whether the {@code octet} is in the base 64 alphabet. * * @param octet * The value to test * @return {@code true} if the value is defined in the base 64 alphabet, {@code false} otherwise. */ public static boolean isBase64(final byte octet) { return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); } /** * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the * method treats whitespace as valid. * * @param arrayOctet * byte array to test * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; * {@code false}, otherwise */ public static boolean isBase64(final byte[] arrayOctet) { for (final byte element : arrayOctet) { if (!isBase64(element) && !Character.isWhitespace(element)) { return false; } } return true; } /** * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the * method treats whitespace as valid. * * @param base64 * String to test * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if * the String is empty; {@code false}, otherwise */ public static boolean isBase64(final String base64) { return isBase64(getBytes(base64, Charsets.DEFAULT)); } /** * Searches for the first occurrence of an email address within the given CharSequence. * * This method uses a regular expression to find an email address in the input CharSequence. * If an email address is found, it is returned; otherwise, the method returns {@code null}. * * @param cs The CharSequence to be searched. It can be {@code null} or empty. * @return The first email address found in the CharSequence, or {@code null} if no email address is found. * @see #isValidEmailAddress(CharSequence) * @see #findAllEmailAddresses(CharSequence) */ public static String findFirstEmailAddress(final CharSequence cs) { if (isEmpty(cs)) { return null; } final Matcher matcher = EMAIL_ADDRESS_RFC_5322_PATTERN.matcher(cs); // ^[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$" // Matcher matcher = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+").matcher(str); if (matcher.find()) { return matcher.group(); } return null; } /** * Finds all the email addresses in the given CharSequence. * * This method uses a regular expression to find all occurrences of email addresses in the input CharSequence. * It returns a list of all found email addresses. If no email address is found, it returns an empty list. * * @param cs The CharSequence to be searched. It can be {@code null} or empty. * @return A list of all found email addresses, or an empty list if no email address is found. * @see #isValidEmailAddress(CharSequence) * @see #findFirstEmailAddress(CharSequence) */ public static List findAllEmailAddresses(final CharSequence cs) { if (isEmpty(cs)) { return new ArrayList<>(); } final Matcher matcher = EMAIL_ADDRESS_RFC_5322_PATTERN.matcher(cs); final List result = new ArrayList<>(); while (matcher.find()) { result.add(matcher.group()); } return result; } // /** // * Applies the given function to each element of the provided array of CharSequences. // * The function should take a CharSequence as input and return a CharSequence. // * // * @param The type of the elements in the array, which extends CharSequence. // * @param a The array of CharSequences to which the function will be applied. // * @param converter The function to apply to each element of the array. // * @throws IllegalArgumentException if the converter function is {@code null}. // * @see #copyThenTrim(String[]) // * @see #copyThenStrip(String[]) // * @see #copyThenSetAll(CharSequence[], Function) // * @see N#setAll(Object[], java.util.function.IntFunction) // * @see N#setAll(Object[], Throwables.IntObjFunction) // * @see N#replaceAll(Object[], java.util.function.UnaryOperator) // */ // @Beta // public static void setAll(final T[] a, final Function converter) throws IllegalArgumentException { // N.checkArgNotNull(converter); // // if (N.isEmpty(a)) { // return; // } // // for (int i = 0, len = a.length; i < len; i++) { // a[i] = converter.apply(a[i]); // } // } // // /** // * Creates a copy of the given array and sets all elements in the copy using the provided converter function. // * If the specified array is {@code null}, returns {@code null}. // * If the specified array is empty, returns itself. // * // * @param The type of the elements in the array, which extends CharSequence. // * @param a The array of CharSequences to which the function will be applied. May be {@code null}. // * @param converter The function to apply to each element of the array. // * @return A new array with the transformed elements. Returns {@code null} if the input array is {@code null}. // * @see #copyThenTrim(String[]) // * @see #copyThenStrip(String[]) // * @see N#copyThenSetAll(Object[], java.util.function.IntFunction) // * @see N#copyThenSetAll(Object[], Throwables.IntObjFunction) // */ // @Beta // @MayReturnNull // public static T[] copyThenSetAll(final T[] a, final Function converter) { // N.checkArgNotNull(converter); // // if (a == null) { // return null; // NOSONAR // } else if (a.length == 0) { // return a.clone(); // } // // final T[] copy = a.clone(); // // for (int i = 0, len = a.length; i < len; i++) { // copy[i] = converter.apply(a[i]); // } // // return a; // } /** * Creates a copy of the given array of strings and trims each string in the array. * Trimming a string removes any leading or trailing whitespace. * * @param strs The array of strings to be copied and trimmed. May be {@code null}. * @return A new array with the trimmed strings. Returns {@code null} if the input array is {@code null}. * @see N#copyThenReplaceAll(Object[], java.util.function.UnaryOperator) * @see Fn#trim() * @see Fn#trimToEmpty() * @see Fn#trimToNull() */ @Beta @MayReturnNull public static String[] copyThenTrim(final String[] strs) { return N.copyThenReplaceAll(strs, Fn.trim()); } /** * Creates a copy of the given array of strings and strips each string in the array. * Stripping a string removes any leading or trailing whitespace. * * @param strs The array of strings to be copied and stripped. May be {@code null}. * @return A new array with the stripped strings. Returns {@code null} if the input array is {@code null}. * @see N#copyThenReplaceAll(Object[], java.util.function.UnaryOperator) * @see Fn#strip() * @see Fn#stripToEmpty() * @see Fn#stripToNull() */ @Beta @MayReturnNull public static String[] copyThenStrip(final String[] strs) { return N.copyThenReplaceAll(strs, Fn.strip()); } static void checkInputChars(final char[] chs, final String parameterName, final boolean canBeNullOrEmpty) { if (!canBeNullOrEmpty && N.isEmpty(chs)) { throw new IllegalArgumentException("Input char array or String parameter '" + parameterName + "' can't be null or empty"); } for (final char ch : chs) { if (Character.isLowSurrogate(ch) || Character.isHighSurrogate(ch)) { throw new IllegalArgumentException("Element char in the input char array or String parameter '" + parameterName + "' can't be low-surrogate or high-surrogate code unit. Please consider using String or String array instead if input parameter is char array"); } } } static int calculateBufferSize(final int len, final int elementPlusDelimiterLen) { return len > Integer.MAX_VALUE / elementPlusDelimiterLen ? Integer.MAX_VALUE : len * elementPlusDelimiterLen; } static int calculateBufferSize(final int len, final int elementPlusDelimiterLen, final int prefixLen, final int suffixLen) { return len > (Integer.MAX_VALUE - prefixLen - suffixLen) / elementPlusDelimiterLen ? Integer.MAX_VALUE : len * elementPlusDelimiterLen + prefixLen + suffixLen; } /** * @deprecated replaced by {@code Strings} */ @Deprecated @Beta public static final class StringUtil extends Strings { private StringUtil() { // Utility class. } } public static final class StrUtil { private StrUtil() { // Utility class. } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param inclusiveBeginIndex * @return * @see Strings#substring(String, int) */ public static Optional substring(final String str, final int inclusiveBeginIndex) { return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param inclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substring(String, int, int) */ public static Optional substring(final String str, final int inclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, exclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param inclusiveBeginIndex * @param funcOfExclusiveEndIndex * @return * @see Strings#substring(String, int, IntUnaryOperator) */ public static Optional substring(final String str, final int inclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex)); } // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param inclusiveBeginIndex // * @param funcOfExclusiveEndIndex // * @return // * @see #substring(String, int, int) // */ // @Beta // public static Optional substring(final String str, final int inclusiveBeginIndex, // final BiFunction funcOfExclusiveEndIndex) { // return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex)); // } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param funcOfInclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substring(String, IntUnaryOperator, int) */ public static Optional substring(final String str, final IntUnaryOperator funcOfInclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substring(str, funcOfInclusiveBeginIndex, exclusiveEndIndex)); } // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param funcOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @return // * @see #substring(String, int, int) // */ // @Beta // public static Optional substring(final String str, final BiFunction funcOfInclusiveBeginIndex, // final int exclusiveEndIndex) { // return Optional.ofNullable(Strings.substring(str, funcOfInclusiveBeginIndex, exclusiveEndIndex)); // } // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @return // * @see Strings#substring(String, char) // * @deprecated // */ // @Deprecated // public static Optional substring(String str, char delimiterOfInclusiveBeginIndex) { // return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex)); // } // // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @return // * @see Strings#substring(String, String) // * @deprecated // */ // @Deprecated // public static Optional substring(String str, String delimiterOfInclusiveBeginIndex) { // return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex)); // } // // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param inclusiveBeginIndex // * @param delimiterOfExclusiveEndIndex // * @return // * @see Strings#substring(String, int, char) // * @deprecated // */ // @Deprecated // public static Optional substring(String str, int inclusiveBeginIndex, char delimiterOfExclusiveEndIndex) { // return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex)); // } // // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param inclusiveBeginIndex // * @param delimiterOfExclusiveEndIndex // * @return // * @see Strings#substring(String, int, String) // * @deprecated // */ // @Deprecated // public static Optional substring(String str, int inclusiveBeginIndex, String delimiterOfExclusiveEndIndex) { // return Optional.ofNullable(Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex)); // } // // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @return // * @see Strings#substring(String, char, int) // * @deprecated // */ // @Deprecated // public static Optional substring(String str, char delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) { // return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex)); // } // // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @return // * @see Strings#substring(String, String, int) // * @deprecated // */ // @Deprecated // public static Optional substring(String str, String delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) { // return Optional.ofNullable(Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex)); // } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param inclusiveBeginIndex * @param defaultStr * @return * @see Strings#substringAfter(String, char) */ @Beta public static String substringOrElse(final String str, final int inclusiveBeginIndex, final String defaultStr) { final String ret = Strings.substring(str, inclusiveBeginIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param inclusiveBeginIndex * @param exclusiveEndIndex * @param defaultStr * @return * @see Strings#substring(String, int, int) */ @Beta public static String substringOrElse(final String str, final int inclusiveBeginIndex, final int exclusiveEndIndex, final String defaultStr) { final String ret = Strings.substring(str, inclusiveBeginIndex, exclusiveEndIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param inclusiveBeginIndex * @param funcOfExclusiveEndIndex * @param defaultStr * @return * @see Strings#substring(String, int, IntUnaryOperator) */ @Beta public static String substringOrElse(final String str, final int inclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex, final String defaultStr) { final String ret = Strings.substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param funcOfInclusiveBeginIndex * @param exclusiveEndIndex * @param defaultStr * @return * @see Strings#substring(String, IntUnaryOperator, int) */ @Beta public static String substringOrElse(final String str, final IntUnaryOperator funcOfInclusiveBeginIndex, final int exclusiveEndIndex, final String defaultStr) { final String ret = Strings.substring(str, funcOfInclusiveBeginIndex, exclusiveEndIndex); return ret == null ? defaultStr : ret; } // /** // * Returns the substring if it exists, otherwise returns {@code defaultStr}. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param defaultStr // * @return // * @see Strings#substring(String, char) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElse(String str, char delimiterOfInclusiveBeginIndex, final String defaultStr) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex); // // return ret == null ? defaultStr : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code defaultStr}. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param defaultStr // * @return // * @see Strings#substring(String, String) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElse(String str, String delimiterOfInclusiveBeginIndex, final String defaultStr) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex); // // return ret == null ? defaultStr : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code defaultStr}. // * // * @param str // * @param inclusiveBeginIndex // * @param delimiterOfExclusiveEndIndex // * @param defaultStr // * @return // * @see Strings#substring(String, int, char) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElse(String str, int inclusiveBeginIndex, char delimiterOfExclusiveEndIndex, final String defaultStr) { // final String ret = Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex); // // return ret == null ? defaultStr : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code defaultStr}. // * // * @param str // * @param inclusiveBeginIndex // * @param delimiterOfExclusiveEndIndex // * @param defaultStr // * @return // * @see Strings#substring(String, int, String) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElse(String str, int inclusiveBeginIndex, String delimiterOfExclusiveEndIndex, final String defaultStr) { // final String ret = Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex); // // return ret == null ? defaultStr : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code defaultStr}. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @param defaultStr // * @return // * @see Strings#substring(String, char, int) // * @deprecated // */ // @Beta // public static String substringOrElse(String str, char delimiterOfInclusiveBeginIndex, int exclusiveEndIndex, final String defaultStr) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex); // // return ret == null ? defaultStr : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code defaultStr}. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @param defaultStr // * @return // * @see Strings#substring(String, String, int) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElse(String str, String delimiterOfInclusiveBeginIndex, int exclusiveEndIndex, final String defaultStr) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex); // // return ret == null ? defaultStr : ret; // } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param inclusiveBeginIndex * @return * @see Strings#substringAfter(String, char) */ @Beta public static String substringOrElseItself(final String str, final int inclusiveBeginIndex) { final String ret = Strings.substring(str, inclusiveBeginIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param inclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substring(String, int, int) */ @Beta public static String substringOrElseItself(final String str, final int inclusiveBeginIndex, final int exclusiveEndIndex) { final String ret = Strings.substring(str, inclusiveBeginIndex, exclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param inclusiveBeginIndex * @param funcOfExclusiveEndIndex * @return * @see Strings#substring(String, int, IntUnaryOperator) */ @Beta public static String substringOrElseItself(final String str, final int inclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { final String ret = Strings.substring(str, inclusiveBeginIndex, funcOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param funcOfInclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substring(String, IntUnaryOperator, int) */ @Beta public static String substringOrElseItself(final String str, final IntUnaryOperator funcOfInclusiveBeginIndex, final int exclusiveEndIndex) { final String ret = Strings.substring(str, funcOfInclusiveBeginIndex, exclusiveEndIndex); return ret == null ? str : ret; } // /** // * Returns the substring if it exists, otherwise returns {@code str} itself. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @return // * @see Strings#substring(String, char) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElseItself(String str, char delimiterOfInclusiveBeginIndex) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex); // // return ret == null ? str : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code str} itself. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @return // * @see Strings#substring(String, String) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElseItself(String str, String delimiterOfInclusiveBeginIndex) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex); // // return ret == null ? str : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code str} itself. // * // * @param str // * @param inclusiveBeginIndex // * @param delimiterOfExclusiveEndIndex // * @return // * @see Strings#substring(String, int, char) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElseItself(String str, int inclusiveBeginIndex, char delimiterOfExclusiveEndIndex) { // final String ret = Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex); // // return ret == null ? str : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code str} itself. // * // * @param str // * @param inclusiveBeginIndex // * @param delimiterOfExclusiveEndIndex // * @return // * @see Strings#substring(String, int, String) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElseItself(String str, int inclusiveBeginIndex, String delimiterOfExclusiveEndIndex) { // final String ret = Strings.substring(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex); // // return ret == null ? str : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code str} itself. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @return // * @see Strings#substring(String, char, int) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElseItself(String str, char delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex); // // return ret == null ? str : ret; // } // // /** // * Returns the substring if it exists, otherwise returns {@code str} itself. // * // * @param str // * @param delimiterOfInclusiveBeginIndex // * @param exclusiveEndIndex // * @return // * @see Strings#substring(String, String, int) // * @deprecated // */ // @Deprecated // @Beta // public static String substringOrElseItself(String str, String delimiterOfInclusiveBeginIndex, int exclusiveEndIndex) { // final String ret = Strings.substring(str, delimiterOfInclusiveBeginIndex, exclusiveEndIndex); // // return ret == null ? str : ret; // } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfter(String, char) */ @Beta public static Optional substringAfter(final String str, final char delimiterOfExclusiveBeginIndex) { return Optional.ofNullable(Strings.substringAfter(str, delimiterOfExclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfter(String, String) */ @Beta public static Optional substringAfter(final String str, final String delimiterOfExclusiveBeginIndex) { return Optional.ofNullable(Strings.substringAfter(str, delimiterOfExclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringAfter(String, String, int) */ @Beta public static Optional substringAfter(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substringAfter(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfterLast(String, String) */ @Beta public static Optional substringAfterLast(final String str, final char delimiterOfExclusiveBeginIndex) { return Optional.ofNullable(Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfterLast(String, String) */ @Beta public static Optional substringAfterLast(final String str, final String delimiterOfExclusiveBeginIndex) { return Optional.ofNullable(Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringAfterLast(String, String, int) */ @Beta public static Optional substringAfterLast(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimitersOfExclusiveBeginIndex * @return * @see Strings#substringAfterAny(String, char...) */ @Beta public static Optional substringAfterAny(final String str, final char... delimitersOfExclusiveBeginIndex) { return Optional.ofNullable(Strings.substringAfterAny(str, delimitersOfExclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimitersOfExclusiveBeginIndex * @return * @see Strings#substringAfterAny(String, String...) */ @Beta public static Optional substringAfterAny(final String str, final String... delimitersOfExclusiveBeginIndex) { return Optional.ofNullable(Strings.substringAfterAny(str, delimitersOfExclusiveBeginIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBefore(String, String) */ @Beta public static Optional substringBefore(final String str, final char delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBefore(str, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBefore(String, String) */ @Beta public static Optional substringBefore(final String str, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBefore(str, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBefore(String, int, String) */ @Beta public static Optional substringBefore(final String str, final int inclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBefore(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBeforeLast(String, String) */ @Beta public static Optional substringBeforeLast(final String str, final char delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBeforeLast(str, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBeforeLast(String, String) */ @Beta public static Optional substringBeforeLast(final String str, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBeforeLast(str, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBeforeLast(String, int, String) */ @Beta public static Optional substringBeforeLast(final String str, final int inclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBeforeLast(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimitersOfExclusiveEndIndex * @return * @see Strings#substringBeforeAny(String, char...) */ @Beta public static Optional substringBeforeAny(final String str, final char... delimitersOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBeforeAny(str, delimitersOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimitersOfExclusiveEndIndex * @return * @see Strings#substringBeforeAny(String, String...) */ @Beta public static Optional substringBeforeAny(final String str, final String... delimitersOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBeforeAny(str, delimitersOfExclusiveEndIndex)); } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param defaultStr * @return * @see Strings#substringAfter(String, String) */ @Beta public static String substringAfterOrElse(final String str, final String delimiterOfExclusiveBeginIndex, final String defaultStr) { final String ret = Strings.substringAfter(str, delimiterOfExclusiveBeginIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param defaultStr * @return * @see Strings#substringAfterLast(String, String) */ @Beta public static String substringAfterLastOrElse(final String str, final String delimiterOfExclusiveBeginIndex, final String defaultStr) { final String ret = Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param delimiterOfExclusiveEndIndex * @param defaultStr * @return * @see Strings#substringBefore(String, String) */ @Beta public static String substringBeforeOrElse(final String str, final String delimiterOfExclusiveEndIndex, final String defaultStr) { final String ret = Strings.substringBefore(str, delimiterOfExclusiveEndIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code defaultStr}. * * @param str * @param delimiterOfExclusiveEndIndex * @param defaultStr * @return * @see Strings#substringBeforeLast(String, String) */ @Beta public static String substringBeforeLastOrElse(final String str, final String delimiterOfExclusiveEndIndex, final String defaultStr) { final String ret = Strings.substringBeforeLast(str, delimiterOfExclusiveEndIndex); return ret == null ? defaultStr : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfter(String, char) */ @Beta public static String substringAfterOrElseItself(final String str, final char delimiterOfExclusiveBeginIndex) { final String ret = Strings.substringAfter(str, delimiterOfExclusiveBeginIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfter(String, String) */ @Beta public static String substringAfterOrElseItself(final String str, final String delimiterOfExclusiveBeginIndex) { final String ret = Strings.substringAfter(str, delimiterOfExclusiveBeginIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringAfter(String, String) */ @Beta public static String substringAfterOrElseItself(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { final String ret = Strings.substringAfter(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfterLast(String, String) */ @Beta public static String substringAfterLastOrElseItself(final String str, final char delimiterOfExclusiveBeginIndex) { final String ret = Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveBeginIndex * @return * @see Strings#substringAfterLast(String, String) */ @Beta public static String substringAfterLastOrElseItself(final String str, final String delimiterOfExclusiveBeginIndex) { final String ret = Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringAfterLast(String, String) */ @Beta public static String substringAfterLastOrElseItself(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { final String ret = Strings.substringAfterLast(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBefore(String, String) */ @Beta public static String substringBeforeOrElseItself(final String str, final char delimiterOfExclusiveEndIndex) { final String ret = Strings.substringBefore(str, delimiterOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBefore(String, String) */ @Beta public static String substringBeforeOrElseItself(final String str, final String delimiterOfExclusiveEndIndex) { final String ret = Strings.substringBefore(str, delimiterOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param inclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBefore(String, String) */ @Beta public static String substringBeforeOrElseItself(final String str, final int inclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { final String ret = Strings.substringBefore(str, inclusiveBeginIndex, delimiterOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBeforeLast(String, String) */ @Beta public static String substringBeforeLastOrElseItself(final String str, final char delimiterOfExclusiveEndIndex) { final String ret = Strings.substringBeforeLast(str, delimiterOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBeforeLast(String, String) */ @Beta public static String substringBeforeLastOrElseItself(final String str, final String delimiterOfExclusiveEndIndex) { final String ret = Strings.substringBeforeLast(str, delimiterOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns the substring if it exists, otherwise returns {@code str} itself. * * @param str * @param exclusiveEndIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBeforeLast(String, String) */ @Beta public static String substringBeforeLastOrElseItself(final String str, final int exclusiveEndIndex, final String delimiterOfExclusiveEndIndex) { final String ret = Strings.substringBeforeLast(str, exclusiveEndIndex, delimiterOfExclusiveEndIndex); return ret == null ? str : ret; } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param exclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringBetween(String, int, int) */ public static Optional substringBetween(final String str, final int exclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, exclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param exclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBetween(String, int, char) */ public static Optional substringBetween(final String str, final int exclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param exclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBetween(String, int, String) */ public static Optional substringBetween(final String str, final int exclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringBetween(String, char, int) */ public static Optional substringBetween(final String str, final char delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringBetween(String, String, int) */ public static Optional substringBetween(final String str, final String delimiterOfExclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, exclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBetween(String, char, char) */ public static Optional substringBetween(final String str, final char delimiterOfExclusiveBeginIndex, final char delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param tag * @return * @see #substringBetween(String, String, String) * @see #substringBetween(String, int, int) */ public static Optional substringBetween(final String str, final String tag) { return substringBetween(str, tag, tag); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see Strings#substringBetween(String, String, String) */ public static Optional substringBetween(final String str, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param fromIndex * @param delimiterOfExclusiveBeginIndex * @param delimiterOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ public static Optional substringBetween(final String str, final int fromIndex, final String delimiterOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, fromIndex, delimiterOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param exclusiveBeginIndex * @param funcOfExclusiveEndIndex * @return * @see Strings#substringBetween(String, int, IntUnaryOperator) */ public static Optional substringBetween(final String str, final int exclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex)); } // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param exclusiveBeginIndex // * @param funcOfExclusiveEndIndex {@code exclusiveEndIndex <- funcOfExclusiveEndIndex.apply(str, exclusiveBeginIndex) if inclusiveBeginIndex >= 0} // * @return // * @see #substringBetween(String, int, int) // */ // @Beta // public static Optional substringBetween(final String str, final int exclusiveBeginIndex, // final BiFunction funcOfExclusiveEndIndex) { // return Optional.ofNullable(Strings.substringBetween(str, exclusiveBeginIndex, funcOfExclusiveEndIndex)); // } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param funcOfExclusiveBeginIndex * @param exclusiveEndIndex * @return * @see Strings#substringBetween(String, IntUnaryOperator, int) */ public static Optional substringBetween(final String str, final IntUnaryOperator funcOfExclusiveBeginIndex, final int exclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, funcOfExclusiveBeginIndex, exclusiveEndIndex)); } // /** // * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional} // * // * @param str // * @param funcOfExclusiveBeginIndex {@code exclusiveBeginIndex <- funcOfExclusiveBeginIndex.apply(str, exclusiveEndIndex)) if exclusiveEndIndex >= 0} // * @param exclusiveEndIndex // * @return // * @see #substringBetween(String, int, int) // */ // @Beta // public static Optional substringBetween(final String str, final BiFunction funcOfExclusiveBeginIndex, // final int exclusiveEndIndex) { // return Optional.ofNullable(Strings.substringBetween(str, funcOfExclusiveBeginIndex, exclusiveEndIndex)); // } /** * Returns {@code Optional} with value of the substring if it exists, otherwise returns an empty {@code Optional}. * * @param str * @param delimiterOfExclusiveBeginIndex * @param funcOfExclusiveEndIndex * @return * @see #substringBetween(String, int, int) */ public static Optional substringBetween(final String str, final String delimiterOfExclusiveBeginIndex, final IntUnaryOperator funcOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, delimiterOfExclusiveBeginIndex, funcOfExclusiveEndIndex)); } /** * * @param str * @param funcOfExclusiveBeginIndex (exclusiveBeginIndex <- funcOfExclusiveBeginIndex.applyAsInt(exclusiveEndIndex)) * @param delimiterOfExclusiveEndIndex (exclusiveEndIndex <- str.lastIndexOf(delimiterOfExclusiveEndIndex)) * @return * @see #substringBetween(String, int, int) */ public static Optional substringBetween(final String str, final IntUnaryOperator funcOfExclusiveBeginIndex, final String delimiterOfExclusiveEndIndex) { return Optional.ofNullable(Strings.substringBetween(str, funcOfExclusiveBeginIndex, delimiterOfExclusiveEndIndex)); } /** * Returns an Optional containing the first non-empty CharSequence from the given two CharSequences. * If both CharSequences are empty, returns an empty Optional. * * @param the type of the CharSequence * @param a the first CharSequence to check * @param b the second CharSequence to check * @return an Optional containing the first non-empty CharSequence, or an empty Optional if both are empty */ public static Optional firstNonEmpty(final T a, final T b) { return Strings.isNotEmpty(a) ? Optional.of(a) : (Strings.isNotEmpty(b) ? Optional.of(b) : Optional.empty()); } /** * Returns an Optional containing the first non-empty CharSequence from the given three CharSequences. * If all CharSequences are empty, returns an empty Optional. * * @param the type of the CharSequence * @param a the first CharSequence to check * @param b the second CharSequence to check * @param c the third CharSequence to check * @return an Optional containing the first non-empty CharSequence, or an empty Optional if all are empty */ public static Optional firstNonEmpty(final T a, final T b, final T c) { return Strings.isNotEmpty(a) ? Optional.of(a) : (Strings.isNotEmpty(b) ? Optional.of(b) : (Strings.isNotEmpty(c) ? Optional.of(c) : Optional.empty())); } /** * Returns an Optional containing the first non-empty CharSequence from the given array of CharSequences. * If all CharSequences are empty or the array is empty, returns an empty Optional. * * @param the type of the CharSequence * @param a the array of CharSequences to check, may be {@code null} or empty * @return an Optional containing the first non-empty CharSequence, or an empty Optional if all are empty or the array is empty */ @SafeVarargs public static Optional firstNonEmpty(final T... a) { if (N.isEmpty(a)) { return Optional.empty(); } for (final T e : a) { if (Strings.isNotEmpty(e)) { return Optional.of(e); } } return Optional.empty(); } /** * Returns an Optional containing the first non-blank CharSequence from the given two CharSequences. * If both CharSequences are blank, returns an empty Optional. * * @param the type of the CharSequence * @param a the first CharSequence to check * @param b the second CharSequence to check * @return an Optional containing the first non-blank CharSequence, or an empty Optional if both are blank */ public static Optional firstNonBlank(final T a, final T b) { return Strings.isNotBlank(a) ? Optional.of(a) : (Strings.isNotBlank(b) ? Optional.of(b) : Optional.empty()); } /** * Returns an Optional containing the first non-blank CharSequence from the given three CharSequences. * If all CharSequences are blank, returns an empty Optional. * * @param the type of the CharSequence * @param a the first CharSequence to check * @param b the second CharSequence to check * @param c the third CharSequence to check * @return an Optional containing the first non-blank CharSequence, or an empty Optional if all are blank */ public static Optional firstNonBlank(final T a, final T b, final T c) { return Strings.isNotBlank(a) ? Optional.of(a) : (Strings.isNotBlank(b) ? Optional.of(b) : (Strings.isNotBlank(c) ? Optional.of(c) : Optional.empty())); } /** * Returns an Optional containing the first non-blank CharSequence from the given array of CharSequences. * If all CharSequences are blank or the array is empty, returns an empty Optional. * * @param the type of the CharSequence * @param a the array of CharSequences to check, may be {@code null} or empty * @return an Optional containing the first non-blank CharSequence, or an empty Optional if all are blank or the array is empty */ @SafeVarargs public static Optional firstNonBlank(final T... a) { if (N.isEmpty(a)) { return Optional.empty(); } for (final T e : a) { if (Strings.isNotBlank(e)) { return Optional.of(e); } } return Optional.empty(); } /** * Returns an empty {@code OptionalInt} if the specified string is blank or a invalid integer string. Otherwise returns {@code OptionalInt} with value converted from the specified String. * * @param str * @return * @see Numbers#createInteger(String) */ @Beta public static u.OptionalInt createInteger(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.OptionalInt.empty(); } try { return u.OptionalInt.of(Numbers.createInteger(str)); } catch (final NumberFormatException e) { return u.OptionalInt.empty(); } } /** * Returns an empty {@code OptionalLong} if the specified string is blank or a invalid long string. Otherwise returns {@code OptionalLong} with value converted from the specified String. * * @param str * @return * @see Numbers#createLong(String) */ @Beta public static u.OptionalLong createLong(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.OptionalLong.empty(); } try { return u.OptionalLong.of(Numbers.createLong(str)); } catch (final NumberFormatException e) { return u.OptionalLong.empty(); } } /** * Returns an empty {@code OptionalFloat} if the specified string is blank or a invalid float string. Otherwise returns {@code OptionalFloat} with value converted from the specified String. * * @param str * @return * @see Numbers#createFloat(String) */ @Beta public static u.OptionalFloat createFloat(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.OptionalFloat.empty(); } try { return u.OptionalFloat.of(Numbers.createFloat(str)); } catch (final NumberFormatException e) { return u.OptionalFloat.empty(); } } /** * Returns an empty {@code OptionalDouble} if the specified string is blank or a invalid double string. Otherwise returns {@code OptionalDouble} with value converted from the specified String. * * @param str * @return * @see Numbers#createDouble(String) */ @Beta public static u.OptionalDouble createDouble(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.OptionalDouble.empty(); } try { return u.OptionalDouble.of(Numbers.createDouble(str)); } catch (final NumberFormatException e) { return u.OptionalDouble.empty(); } } /** * Returns an empty {@code Optional} if the specified string is blank or a invalid {@code BigInteger} string. Otherwise returns {@code Optional} with value converted from the specified String. * * @param str * @return * @see Numbers#createBigInteger(String) */ @Beta public static u.Optional createBigInteger(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.Optional.empty(); } try { return u.Optional.of(Numbers.createBigInteger(str)); } catch (final NumberFormatException e) { return u.Optional.empty(); } } /** * Returns an empty {@code Optional} if the specified string is blank or a invalid {@code BigDecimal} string. Otherwise returns {@code Optional} with value converted from the specified String. * * @param str * @return * @see Numbers#createBigDecimal(String) */ @Beta public static u.Optional createBigDecimal(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.Optional.empty(); } try { return u.Optional.of(Numbers.createBigDecimal(str)); } catch (final NumberFormatException e) { return u.Optional.empty(); } } /** * Returns an empty {@code Optional} if the specified string is blank or a invalid number string. Otherwise returns {@code Optional} with value converted from the specified String. * * @param str * @return * @see Numbers#createNumber(String) */ @Beta public static u.Optional createNumber(final String str) { if (!Numbers.quickCheckForIsCreatable(str)) { return u.Optional.empty(); } try { return u.Optional.of(Numbers.createNumber(str)); } catch (final NumberFormatException e) { return u.Optional.empty(); } } } }




    © 2015 - 2025 Weber Informatics LLC | Privacy Policy