    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      https://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.io.UnsupportedEncodingException;
    020import java.nio.CharBuffer;
    021import java.nio.charset.Charset;
    022import java.text.Normalizer;
    023import java.util.ArrayList;
    024import java.util.Arrays;
    025import java.util.Iterator;
    026import java.util.List;
    027import java.util.Locale;
    028import java.util.Objects;
    029import java.util.Set;
    030import java.util.function.Supplier;
    031import java.util.regex.Pattern;
    032import java.util.stream.Collectors;
    033
    034import org.apache.commons.lang3.function.Suppliers;
    035import org.apache.commons.lang3.stream.LangCollectors;
    036import org.apache.commons.lang3.stream.Streams;
    037
    038/**
    039 * Operations on {@link String} that are
    040 * {@code null} safe.
    041 *
    042 * <ul>
    043 *  <li><strong>IsEmpty/IsBlank</strong>
    044 *      - checks if a String contains text</li>
    045 *  <li><strong>Trim/Strip</strong>
    046 *      - removes leading and trailing whitespace</li>
    047 *  <li><strong>Equals/Compare</strong>
    048 *      - compares two strings in a null-safe manner</li>
    049 *  <li><strong>startsWith</strong>
    050 *      - check if a String starts with a prefix in a null-safe manner</li>
    051 *  <li><strong>endsWith</strong>
    052 *      - check if a String ends with a suffix in a null-safe manner</li>
    053 *  <li><strong>IndexOf/LastIndexOf/Contains</strong>
    054 *      - null-safe index-of checks
    055 *  <li><strong>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</strong>
    056 *      - index-of any of a set of Strings</li>
    057 *  <li><strong>ContainsOnly/ContainsNone/ContainsAny</strong>
    058 *      - checks if String contains only/none/any of these characters</li>
    059 *  <li><strong>Substring/Left/Right/Mid</strong>
    060 *      - null-safe substring extractions</li>
    061 *  <li><strong>SubstringBefore/SubstringAfter/SubstringBetween</strong>
    062 *      - substring extraction relative to other strings</li>
    063 *  <li><strong>Split/Join</strong>
    064 *      - splits a String into an array of substrings and vice versa</li>
    065 *  <li><strong>Remove/Delete</strong>
    066 *      - removes part of a String</li>
    067 *  <li><strong>Replace/Overlay</strong>
    068 *      - Searches a String and replaces one String with another</li>
    069 *  <li><strong>Chomp/Chop</strong>
    070 *      - removes the last part of a String</li>
    071 *  <li><strong>AppendIfMissing</strong>
    072 *      - appends a suffix to the end of the String if not present</li>
    073 *  <li><strong>PrependIfMissing</strong>
    074 *      - prepends a prefix to the start of the String if not present</li>
    075 *  <li><strong>LeftPad/RightPad/Center/Repeat</strong>
    076 *      - pads a String</li>
    077 *  <li><strong>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</strong>
    078 *      - changes the case of a String</li>
    079 *  <li><strong>CountMatches</strong>
    080 *      - counts the number of occurrences of one String in another</li>
    081 *  <li><strong>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</strong>
    082 *      - checks the characters in a String</li>
    083 *  <li><strong>DefaultString</strong>
    084 *      - protects against a null input String</li>
    085 *  <li><strong>Rotate</strong>
    086 *      - rotate (circular shift) a String</li>
    087 *  <li><strong>Reverse/ReverseDelimited</strong>
    088 *      - reverses a String</li>
    089 *  <li><strong>Abbreviate</strong>
    090 *      - abbreviates a string using ellipses or another given String</li>
    091 *  <li><strong>Difference</strong>
    092 *      - compares Strings and reports on their differences</li>
    093 *  <li><strong>LevenshteinDistance</strong>
    094 *      - the number of changes needed to change one String into another</li>
    095 * </ul>
    096 *
    097 * <p>The {@link StringUtils} class defines certain words related to
    098 * String handling.</p>
    099 *
    100 * <ul>
    101 *  <li>null - {@code null}</li>
    102 *  <li>empty - a zero-length string ({@code ""})</li>
    103 *  <li>space - the space character ({@code ' '}, char 32)</li>
    104 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
    105 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
    106 * </ul>
    107 *
    108 * <p>{@link StringUtils} handles {@code null} input Strings quietly.
    109 * That is to say that a {@code null} input will return {@code null}.
    110 * Where a {@code boolean} or {@code int} is being returned
    111 * details vary by method.</p>
    112 *
    113 * <p>A side effect of the {@code null} handling is that a
    114 * {@link NullPointerException} should be considered a bug in
    115 * {@link StringUtils}.</p>
    116 *
    117 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
    118 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
    119 *
    120 * <p>#ThreadSafe#</p>
    121 * @see String
    122 * @since 1.0
    123 */
    124//@Immutable
    125public class StringUtils {
    126
    127    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
    128    // Whitespace:
    129    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
    130    // where WHITESPACE is a string of all whitespace characters
    131    //
    132    // Character access:
    133    // String.charAt(n) versus toCharArray(), then array[n]
    134    // String.charAt(n) is about 15% worse for a 10K string
    135    // They are about equal for a length 50 string
    136    // String.charAt(n) is about 4 times better for a length 3 string
    137    // String.charAt(n) is best bet overall
    138    //
    139    // Append:
    140    // String.concat about twice as fast as StringBuffer.append
    141    // (not sure who tested this)
    142
    143    /**
    144     * This is a 3 character version of an ellipsis. There is a Unicode character for a HORIZONTAL ELLIPSIS, U+2026 … this isn't it.
    145     */
    146    private static final String ELLIPSIS3 = "...";
    147
    148    /**
    149     * A String for a space character.
    150     *
    151     * @since 3.2
    152     */
    153    public static final String SPACE = " ";
    154
    155    /**
    156     * The empty String {@code ""}.
    157     * @since 2.0
    158     */
    159    public static final String EMPTY = "";
    160
    161    /**
    162     * The null String {@code null}. Package-private only.
    163     */
    164    static final String NULL = null;
    165
    166    /**
    167     * A String for linefeed LF ("\n").
    168     *
    169     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    170     *      for Character and String Literals</a>
    171     * @since 3.2
    172     */
    173    public static final String LF = "\n";
    174
    175    /**
    176     * A String for carriage return CR ("\r").
    177     *
    178     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    179     *      for Character and String Literals</a>
    180     * @since 3.2
    181     */
    182    public static final String CR = "\r";
    183
    184    /**
    185     * Represents a failed index search.
    186     * @since 2.1
    187     */
    188    public static final int INDEX_NOT_FOUND = -1;
    189
    190    /**
    191     * The maximum size to which the padding constant(s) can expand.
    192     */
    193    private static final int PAD_LIMIT = 8192;
    194
    195    /**
    196     * The default maximum depth at which recursive replacement will continue until no further search replacements are possible.
    197     */
    198    private static final int DEFAULT_TTL = 5;
    199
    200    /**
    201     * Pattern used in {@link #stripAccents(String)}.
    202     */
    203    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
    204
    205    /**
    206     * Abbreviates a String using ellipses. This will turn
    207     * "Now is the time for all good men" into "Now is the time for..."
    208     *
    209     * <p>Specifically:</p>
    210     * <ul>
    211     *   <li>If the number of characters in {@code str} is less than or equal to
    212     *       {@code maxWidth}, return {@code str}.</li>
    213     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
    214     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
    215     *       {@link IllegalArgumentException}.</li>
    216     *   <li>In no case will it return a String of length greater than
    217     *       {@code maxWidth}.</li>
    218     * </ul>
    219     *
    220     * <pre>
    221     * StringUtils.abbreviate(null, *)      = null
    222     * StringUtils.abbreviate("", 4)        = ""
    223     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
    224     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
    225     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
    226     * StringUtils.abbreviate("abcdefg", 4) = "a..."
    227     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
    228     * </pre>
    229     *
    230     * @param str  the String to check, may be null.
    231     * @param maxWidth  maximum length of result String, must be at least 4.
    232     * @return abbreviated String, {@code null} if null String input.
    233     * @throws IllegalArgumentException if the width is too small.
    234     * @since 2.0
    235     */
    236    public static String abbreviate(final String str, final int maxWidth) {
    237        return abbreviate(str, ELLIPSIS3, 0, maxWidth);
    238    }
    239
    240    /**
    241     * Abbreviates a String using ellipses. This will turn "Now is the time for all good men" into "...is the time for..."
    242     *
    243     * <p>
    244     * 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
    245     * leftmost character in the result, or the first character following the ellipses, but it will appear somewhere in the result.
    246     *
    247     * <p>
    248     * In no case will it return a String of length greater than {@code maxWidth}.
    249     * </p>
    250     *
    251     * <pre>
    252     * StringUtils.abbreviate(null, *, *)                = null
    253     * StringUtils.abbreviate("", 0, 4)                  = ""
    254     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
    255     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
    256     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
    257     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
    258     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
    259     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
    260     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
    261     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
    262     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
    263     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
    264     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
    265     * </pre>
    266     *
    267     * @param str      the String to check, may be null.
    268     * @param offset   left edge of source String.
    269     * @param maxWidth maximum length of result String, must be at least 4.
    270     * @return abbreviated String, {@code null} if null String input.
    271     * @throws IllegalArgumentException if the width is too small.
    272     * @since 2.0
    273     */
    274    public static String abbreviate(final String str, final int offset, final int maxWidth) {
    275        return abbreviate(str, ELLIPSIS3, offset, maxWidth);
    276    }
    277
    278    /**
    279     * 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
    280     * "..." was defined as the replacement marker.
    281     *
    282     * <p>
    283     * Specifically:
    284     * </p>
    285     * <ul>
    286     * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
    287     * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
    288     * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an {@link IllegalArgumentException}.</li>
    289     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
    290     * </ul>
    291     *
    292     * <pre>
    293     * StringUtils.abbreviate(null, "...", *)      = null
    294     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
    295     * StringUtils.abbreviate("", "...", 4)        = ""
    296     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
    297     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
    298     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
    299     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
    300     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
    301     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
    302     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
    303     * </pre>
    304     *
    305     * @param str          the String to check, may be null.
    306     * @param abbrevMarker the String used as replacement marker.
    307     * @param maxWidth     maximum length of result String, must be at least {@code abbrevMarker.length + 1}.
    308     * @return abbreviated String, {@code null} if null String input.
    309     * @throws IllegalArgumentException if the width is too small.
    310     * @since 3.6
    311     */
    312    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
    313        return abbreviate(str, abbrevMarker, 0, maxWidth);
    314    }
    315
    316    /**
    317     * 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
    318     * defined as the replacement marker.
    319     *
    320     * <p>
    321     * 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
    322     * be the leftmost character in the result, or the first character following the replacement marker, but it will appear somewhere in the result.
    323     *
    324     * <p>
    325     * In no case will it return a String of length greater than {@code maxWidth}.
    326     * </p>
    327     *
    328     * <pre>
    329     * StringUtils.abbreviate(null, null, *, *)                 = null
    330     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
    331     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
    332     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
    333     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
    334     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
    335     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
    336     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
    337     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
    338     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
    339     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
    340     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
    341     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
    342     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
    343     * </pre>
    344     *
    345     * @param str          the String to check, may be null.
    346     * @param abbrevMarker the String used as replacement marker.
    347     * @param offset       left edge of source String.
    348     * @param maxWidth     maximum length of result String, must be at least 4.
    349     * @return abbreviated String, {@code null} if null String input.
    350     * @throws IllegalArgumentException if the width is too small.
    351     * @since 3.6
    352     */
    353    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
    354        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
    355            return substring(str, 0, maxWidth);
    356        }
    357        if (isAnyEmpty(str, abbrevMarker)) {
    358            return str;
    359        }
    360        final int abbrevMarkerLength = abbrevMarker.length();
    361        final int minAbbrevWidth = abbrevMarkerLength + 1;
    362        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
    363
    364        if (maxWidth < minAbbrevWidth) {
    365            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
    366        }
    367        final int strLen = str.length();
    368        if (strLen <= maxWidth) {
    369            return str;
    370        }
    371        if (offset > strLen) {
    372            offset = strLen;
    373        }
    374        if (strLen - offset < maxWidth - abbrevMarkerLength) {
    375            offset = strLen - (maxWidth - abbrevMarkerLength);
    376        }
    377        if (offset <= abbrevMarkerLength + 1) {
    378            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
    379        }
    380        if (maxWidth < minAbbrevWidthOffset) {
    381            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
    382        }
    383        if (offset + maxWidth - abbrevMarkerLength < strLen) {
    384            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
    385        }
    386        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
    387    }
    388
    389    /**
    390     * Abbreviates a String to the length passed, replacing the middle characters with the supplied replacement String.
    391     *
    392     * <p>
    393     * This abbreviation only occurs if the following criteria is met:
    394     * </p>
    395     * <ul>
    396     * <li>Neither the String for abbreviation nor the replacement String are null or empty</li>
    397     * <li>The length to truncate to is less than the length of the supplied String</li>
    398     * <li>The length to truncate to is greater than 0</li>
    399     * <li>The abbreviated String will have enough room for the length supplied replacement String and the first and last characters of the supplied String for
    400     * abbreviation</li>
    401     * </ul>
    402     * <p>
    403     * Otherwise, the returned String will be the same as the supplied String for abbreviation.
    404     * </p>
    405     *
    406     * <pre>
    407     * StringUtils.abbreviateMiddle(null, null, 0)    = null
    408     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
    409     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
    410     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
    411     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
    412     * </pre>
    413     *
    414     * @param str    the String to abbreviate, may be null.
    415     * @param middle the String to replace the middle characters with, may be null.
    416     * @param length the length to abbreviate {@code str} to.
    417     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
    418     * @since 2.5
    419     */
    420    public static String abbreviateMiddle(final String str, final String middle, final int length) {
    421        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
    422            return str;
    423        }
    424        final int targetSting = length - middle.length();
    425        final int startOffset = targetSting / 2 + targetSting % 2;
    426        final int endOffset = str.length() - targetSting / 2;
    427        return str.substring(0, startOffset) + middle + str.substring(endOffset);
    428    }
    429
    430    /**
    431     * Appends the suffix to the end of the string if the string does not already end with any of the suffixes.
    432     *
    433     * <pre>
    434     * StringUtils.appendIfMissing(null, null)      = null
    435     * StringUtils.appendIfMissing("abc", null)     = "abc"
    436     * StringUtils.appendIfMissing("", "xyz"        = "xyz"
    437     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
    438     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
    439     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
    440     * </pre>
    441     * <p>
    442     * With additional suffixes,
    443     * </p>
    444     *
    445     * <pre>
    446     * StringUtils.appendIfMissing(null, null, null)       = null
    447     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
    448     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
    449     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    450     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
    451     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
    452     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
    453     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
    454     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
    455     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
    456     * </pre>
    457     *
    458     * @param str      The string.
    459     * @param suffix   The suffix to append to the end of the string.
    460     * @param suffixes Additional suffixes that are valid terminators.
    461     * @return A new String if suffix was appended, the same string otherwise.
    462     * @since 3.2
    463     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CS.appendIfMissing(String, CharSequence, CharSequence...)}
    464     */
    465    @Deprecated
    466    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    467        return Strings.CS.appendIfMissing(str, suffix, suffixes);
    468    }
    469
    470    /**
    471     * Appends the suffix to the end of the string if the string does not
    472     * already end, case-insensitive, with any of the suffixes.
    473     *
    474     * <pre>
    475     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
    476     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
    477     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
    478     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
    479     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
    480     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
    481     * </pre>
    482     * <p>With additional suffixes,</p>
    483     * <pre>
    484     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
    485     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
    486     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
    487     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    488     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
    489     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
    490     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
    491     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
    492     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
    493     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
    494     * </pre>
    495     *
    496     * @param str The string.
    497     * @param suffix The suffix to append to the end of the string.
    498     * @param suffixes Additional suffixes that are valid terminators.
    499     * @return A new String if suffix was appended, the same string otherwise.
    500     * @since 3.2
    501     * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CI.appendIfMissing(String, CharSequence, CharSequence...)}
    502     */
    503    @Deprecated
    504    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    505        return Strings.CI.appendIfMissing(str, suffix, suffixes);
    506    }
    507
    508    /**
    509     * Capitalizes a String changing the first character to title case as per {@link Character#toTitleCase(int)}. No other characters are changed.
    510     *
    511     * <p>
    512     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}. A {@code null} input String returns {@code null}.
    513     * </p>
    514     *
    515     * <pre>
    516     * StringUtils.capitalize(null)    = null
    517     * StringUtils.capitalize("")      = ""
    518     * StringUtils.capitalize("cat")   = "Cat"
    519     * StringUtils.capitalize("cAt")   = "CAt"
    520     * StringUtils.capitalize("'cat'") = "'cat'"
    521     * </pre>
    522     *
    523     * @param str the String to capitalize, may be null.
    524     * @return the capitalized String, {@code null} if null String input.
    525     * @see org.apache.commons.text.WordUtils#capitalize(String)
    526     * @see #uncapitalize(String)
    527     * @since 2.0
    528     */
    529    public static String capitalize(final String str) {
    530        if (isEmpty(str)) {
    531            return str;
    532        }
    533        final int firstCodepoint = str.codePointAt(0);
    534        final int newCodePoint = Character.toTitleCase(firstCodepoint);
    535        if (firstCodepoint == newCodePoint) {
    536            // already capitalized
    537            return str;
    538        }
    539        final int[] newCodePoints = str.codePoints().toArray();
    540        newCodePoints[0] = newCodePoint; // copy the first code point
    541        return new String(newCodePoints, 0, newCodePoints.length);
    542    }
    543
    544    /**
    545     * Centers a String in a larger String of size {@code size} using the space character (' ').
    546     *
    547     * <p>
    548     * If the size is less than the String length, the original String is returned. A {@code null} String returns {@code null}. A negative size is treated as
    549     * zero.
    550     * </p>
    551     *
    552     * <p>
    553     * Equivalent to {@code center(str, size, " ")}.
    554     * </p>
    555     *
    556     * <pre>
    557     * StringUtils.center(null, *)   = null
    558     * StringUtils.center("", 4)     = "    "
    559     * StringUtils.center("ab", -1)  = "ab"
    560     * StringUtils.center("ab", 4)   = " ab "
    561     * StringUtils.center("abcd", 2) = "abcd"
    562     * StringUtils.center("a", 4)    = " a  "
    563     * </pre>
    564     *
    565     * @param str  the String to center, may be null.
    566     * @param size the int size of new String, negative treated as zero.
    567     * @return centered String, {@code null} if null String input.
    568     */
    569    public static String center(final String str, final int size) {
    570        return center(str, size, ' ');
    571    }
    572
    573    /**
    574     * Centers a String in a larger String of size {@code size}. Uses a supplied character as the value to pad the String with.
    575     *
    576     * <p>
    577     * If the size is less than the String length, the String is returned. A {@code null} String returns {@code null}. A negative size is treated as zero.
    578     * </p>
    579     *
    580     * <pre>
    581     * StringUtils.center(null, *, *)     = null
    582     * StringUtils.center("", 4, ' ')     = "    "
    583     * StringUtils.center("ab", -1, ' ')  = "ab"
    584     * StringUtils.center("ab", 4, ' ')   = " ab "
    585     * StringUtils.center("abcd", 2, ' ') = "abcd"
    586     * StringUtils.center("a", 4, ' ')    = " a  "
    587     * StringUtils.center("a", 4, 'y')    = "yayy"
    588     * </pre>
    589     *
    590     * @param str     the String to center, may be null.
    591     * @param size    the int size of new String, negative treated as zero.
    592     * @param padChar the character to pad the new String with.
    593     * @return centered String, {@code null} if null String input.
    594     * @since 2.0
    595     */
    596    public static String center(String str, final int size, final char padChar) {
    597        if (str == null || size <= 0) {
    598            return str;
    599        }
    600        final int strLen = str.length();
    601        final int pads = size - strLen;
    602        if (pads <= 0) {
    603            return str;
    604        }
    605        str = leftPad(str, strLen + pads / 2, padChar);
    606        return rightPad(str, size, padChar);
    607    }
    608
    609    /**
    610     * Centers a String in a larger String of size {@code size}. Uses a supplied String as the value to pad the String with.
    611     *
    612     * <p>
    613     * If the size is less than the String length, the String is returned. A {@code null} String returns {@code null}. A negative size is treated as zero.
    614     * </p>
    615     *
    616     * <pre>
    617     * StringUtils.center(null, *, *)     = null
    618     * StringUtils.center("", 4, " ")     = "    "
    619     * StringUtils.center("ab", -1, " ")  = "ab"
    620     * StringUtils.center("ab", 4, " ")   = " ab "
    621     * StringUtils.center("abcd", 2, " ") = "abcd"
    622     * StringUtils.center("a", 4, " ")    = " a  "
    623     * StringUtils.center("a", 4, "yz")   = "yayz"
    624     * StringUtils.center("abc", 7, null) = "  abc  "
    625     * StringUtils.center("abc", 7, "")   = "  abc  "
    626     * </pre>
    627     *
    628     * @param str    the String to center, may be null.
    629     * @param size   the int size of new String, negative treated as zero.
    630     * @param padStr the String to pad the new String with, must not be null or empty.
    631     * @return centered String, {@code null} if null String input.
    632     * @throws IllegalArgumentException if padStr is {@code null} or empty.
    633     */
    634    public static String center(String str, final int size, String padStr) {
    635        if (str == null || size <= 0) {
    636            return str;
    637        }
    638        if (isEmpty(padStr)) {
    639            padStr = SPACE;
    640        }
    641        final int strLen = str.length();
    642        final int pads = size - strLen;
    643        if (pads <= 0) {
    644            return str;
    645        }
    646        str = leftPad(str, strLen + pads / 2, padStr);
    647        return rightPad(str, size, padStr);
    648    }
    649
    650    /**
    651     * Removes one newline from end of a String if it's there, otherwise leave it alone. A newline is &quot;{@code \n}&quot;, &quot;{@code \r}&quot;, or
    652     * &quot;{@code \r\n}&quot;.
    653     *
    654     * <p>
    655     * NOTE: This method changed in 2.0. It now more closely matches Perl chomp.
    656     * </p>
    657     *
    658     * <pre>
    659     * StringUtils.chomp(null)          = null
    660     * StringUtils.chomp("")            = ""
    661     * StringUtils.chomp("abc \r")      = "abc "
    662     * StringUtils.chomp("abc\n")       = "abc"
    663     * StringUtils.chomp("abc\r\n")     = "abc"
    664     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
    665     * StringUtils.chomp("abc\n\r")     = "abc\n"
    666     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
    667     * StringUtils.chomp("\r")          = ""
    668     * StringUtils.chomp("\n")          = ""
    669     * StringUtils.chomp("\r\n")        = ""
    670     * </pre>
    671     *
    672     * @param str the String to chomp a newline from, may be null.
    673     * @return String without newline, {@code null} if null String input.
    674     */
    675    public static String chomp(final String str) {
    676        if (isEmpty(str)) {
    677            return str;
    678        }
    679        if (str.length() == 1) {
    680            final char ch = str.charAt(0);
    681            if (ch == CharUtils.CR || ch == CharUtils.LF) {
    682                return EMPTY;
    683            }
    684            return str;
    685        }
    686        int lastIdx = str.length() - 1;
    687        final char last = str.charAt(lastIdx);
    688        if (last == CharUtils.LF) {
    689            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    690                lastIdx--;
    691            }
    692        } else if (last != CharUtils.CR) {
    693            lastIdx++;
    694        }
    695        return str.substring(0, lastIdx);
    696    }
    697
    698    /**
    699     * Removes {@code separator} from the end of {@code str} if it's there, otherwise leave it alone.
    700     *
    701     * <p>
    702     * NOTE: This method changed in version 2.0. It now more closely matches Perl chomp. For the previous behavior, use
    703     * {@link #substringBeforeLast(String, String)}. This method uses {@link String#endsWith(String)}.
    704     * </p>
    705     *
    706     * <pre>
    707     * StringUtils.chomp(null, *)         = null
    708     * StringUtils.chomp("", *)           = ""
    709     * StringUtils.chomp("foobar", "bar") = "foo"
    710     * StringUtils.chomp("foobar", "baz") = "foobar"
    711     * StringUtils.chomp("foo", "foo")    = ""
    712     * StringUtils.chomp("foo ", "foo")   = "foo "
    713     * StringUtils.chomp(" foo", "foo")   = " "
    714     * StringUtils.chomp("foo", "foooo")  = "foo"
    715     * StringUtils.chomp("foo", "")       = "foo"
    716     * StringUtils.chomp("foo", null)     = "foo"
    717     * </pre>
    718     *
    719     * @param str       the String to chomp from, may be null.
    720     * @param separator separator String, may be null.
    721     * @return String without trailing separator, {@code null} if null String input.
    722     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead.
    723     */
    724    @Deprecated
    725    public static String chomp(final String str, final String separator) {
    726        return Strings.CS.removeEnd(str, separator);
    727    }
    728
    729    /**
    730     * Removes the last character from a String.
    731     *
    732     * <p>
    733     * If the String ends in {@code \r\n}, then remove both of them.
    734     * </p>
    735     *
    736     * <pre>
    737     * StringUtils.chop(null)          = null
    738     * StringUtils.chop("")            = ""
    739     * StringUtils.chop("abc \r")      = "abc "
    740     * StringUtils.chop("abc\n")       = "abc"
    741     * StringUtils.chop("abc\r\n")     = "abc"
    742     * StringUtils.chop("abc")         = "ab"
    743     * StringUtils.chop("abc\nabc")    = "abc\nab"
    744     * StringUtils.chop("a")           = ""
    745     * StringUtils.chop("\r")          = ""
    746     * StringUtils.chop("\n")          = ""
    747     * StringUtils.chop("\r\n")        = ""
    748     * </pre>
    749     *
    750     * @param str the String to chop last character from, may be null.
    751     * @return String without last character, {@code null} if null String input.
    752     */
    753    public static String chop(final String str) {
    754        if (str == null) {
    755            return null;
    756        }
    757        final int strLen = str.length();
    758        if (strLen < 2) {
    759            return EMPTY;
    760        }
    761        final int lastIdx = strLen - 1;
    762        final String ret = str.substring(0, lastIdx);
    763        final char last = str.charAt(lastIdx);
    764        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
    765            return ret.substring(0, lastIdx - 1);
    766        }
    767        return ret;
    768    }
    769
    770    /**
    771     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    772     * <ul>
    773     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    774     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    775     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    776     * </ul>
    777     *
    778     * <p>
    779     * This is a {@code null} safe version of:
    780     * </p>
    781     *
    782     * <pre>
    783     * str1.compareTo(str2)
    784     * </pre>
    785     *
    786     * <p>
    787     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal.
    788     * </p>
    789     *
    790     * <pre>{@code
    791     * StringUtils.compare(null, null)   = 0
    792     * StringUtils.compare(null , "a")   < 0
    793     * StringUtils.compare("a", null)   > 0
    794     * StringUtils.compare("abc", "abc") = 0
    795     * StringUtils.compare("a", "b")     < 0
    796     * StringUtils.compare("b", "a")     > 0
    797     * StringUtils.compare("a", "B")     > 0
    798     * StringUtils.compare("ab", "abc")  < 0
    799     * }</pre>
    800     *
    801     * @param str1 the String to compare from.
    802     * @param str2 the String to compare to
    803     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
    804     * @see #compare(String, String, boolean)
    805     * @see String#compareTo(String)
    806     * @since 3.5
    807     * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}
    808     */
    809    @Deprecated
    810    public static int compare(final String str1, final String str2) {
    811        return Strings.CS.compare(str1, str2);
    812    }
    813
    814    /**
    815     * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    816     * <ul>
    817     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    818     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    819     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    820     * </ul>
    821     *
    822     * <p>
    823     * This is a {@code null} safe version of :
    824     * </p>
    825     *
    826     * <pre>
    827     * str1.compareTo(str2)
    828     * </pre>
    829     *
    830     * <p>
    831     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal.
    832     * </p>
    833     *
    834     * <pre>{@code
    835     * StringUtils.compare(null, null, *)     = 0
    836     * StringUtils.compare(null , "a", true)  < 0
    837     * StringUtils.compare(null , "a", false) > 0
    838     * StringUtils.compare("a", null, true)   > 0
    839     * StringUtils.compare("a", null, false)  < 0
    840     * StringUtils.compare("abc", "abc", *)   = 0
    841     * StringUtils.compare("a", "b", *)       < 0
    842     * StringUtils.compare("b", "a", *)       > 0
    843     * StringUtils.compare("a", "B", *)       > 0
    844     * StringUtils.compare("ab", "abc", *)    < 0
    845     * }</pre>
    846     *
    847     * @param str1       the String to compare from.
    848     * @param str2       the String to compare to.
    849     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
    850     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}.
    851     * @see String#compareTo(String)
    852     * @since 3.5
    853     */
    854    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
    855        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    856            return 0;
    857        }
    858        if (str1 == null) {
    859            return nullIsLess ? -1 : 1;
    860        }
    861        if (str2 == null) {
    862            return nullIsLess ? 1 : -1;
    863        }
    864        return str1.compareTo(str2);
    865    }
    866
    867    /**
    868     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
    869     * <ul>
    870     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    871     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    872     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    873     * </ul>
    874     *
    875     * <p>
    876     * This is a {@code null} safe version of:
    877     * </p>
    878     *
    879     * <pre>
    880     * str1.compareToIgnoreCase(str2)
    881     * </pre>
    882     *
    883     * <p>
    884     * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal. Comparison is case insensitive.
    885     * </p>
    886     *
    887     * <pre>{@code
    888     * StringUtils.compareIgnoreCase(null, null)   = 0
    889     * StringUtils.compareIgnoreCase(null , "a")   < 0
    890     * StringUtils.compareIgnoreCase("a", null)    > 0
    891     * StringUtils.compareIgnoreCase("abc", "abc") = 0
    892     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
    893     * StringUtils.compareIgnoreCase("a", "b")     < 0
    894     * StringUtils.compareIgnoreCase("b", "a")     > 0
    895     * StringUtils.compareIgnoreCase("a", "B")     < 0
    896     * StringUtils.compareIgnoreCase("A", "b")     < 0
    897     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
    898     * }</pre>
    899     *
    900     * @param str1 the String to compare from.
    901     * @param str2 the String to compare to.
    902     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
    903     * @see #compareIgnoreCase(String, String, boolean)
    904     * @see String#compareToIgnoreCase(String)
    905     * @since 3.5
    906     * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}
    907     */
    908    @Deprecated
    909    public static int compareIgnoreCase(final String str1, final String str2) {
    910        return Strings.CI.compare(str1, str2);
    911    }
    912
    913    /**
    914     * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
    915     * <ul>
    916     * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    917     * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    918     * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    919     * </ul>
    920     *
    921     * <p>
    922     * This is a {@code null} safe version of :
    923     * </p>
    924     * <pre>
    925     * str1.compareToIgnoreCase(str2)
    926     * </pre>
    927     *
    928     * <p>
    929     * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal. Comparison is case
    930     * insensitive.
    931     * </p>
    932     *
    933     * <pre>{@code
    934     * StringUtils.compareIgnoreCase(null, null, *)     = 0
    935     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
    936     * StringUtils.compareIgnoreCase(null , "a", false) > 0
    937     * StringUtils.compareIgnoreCase("a", null, true)   > 0
    938     * StringUtils.compareIgnoreCase("a", null, false)  < 0
    939     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
    940     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
    941     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
    942     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
    943     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
    944     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
    945     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
    946     * }</pre>
    947     *
    948     * @param str1       the String to compare from.
    949     * @param str2       the String to compare to.
    950     * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
    951     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
    952     * @see String#compareToIgnoreCase(String)
    953     * @since 3.5
    954     */
    955    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
    956        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    957            return 0;
    958        }
    959        if (str1 == null) {
    960            return nullIsLess ? -1 : 1;
    961        }
    962        if (str2 == null) {
    963            return nullIsLess ? 1 : -1;
    964        }
    965        return str1.compareToIgnoreCase(str2);
    966    }
    967
    968    /**
    969     * Tests if CharSequence contains a search CharSequence, handling {@code null}.
    970     * This method uses {@link String#indexOf(String)} if possible.
    971     *
    972     * <p>A {@code null} CharSequence will return {@code false}.</p>
    973     *
    974     * <pre>
    975     * StringUtils.contains(null, *)     = false
    976     * StringUtils.contains(*, null)     = false
    977     * StringUtils.contains("", "")      = true
    978     * StringUtils.contains("abc", "")   = true
    979     * StringUtils.contains("abc", "a")  = true
    980     * StringUtils.contains("abc", "z")  = false
    981     * </pre>
    982     *
    983     * @param seq  the CharSequence to check, may be null
    984     * @param searchSeq  the CharSequence to find, may be null
    985     * @return true if the CharSequence contains the search CharSequence,
    986     *  false if not or {@code null} string input
    987     * @since 2.0
    988     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
    989     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}
    990     */
    991    @Deprecated
    992    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
    993        return Strings.CS.contains(seq, searchSeq);
    994    }
    995
    996    /**
    997     * Tests if CharSequence contains a search character, handling {@code null}. This method uses {@link String#indexOf(int)} if possible.
    998     *
    999     * <p>
    1000     * A {@code null} or empty ("") CharSequence will return {@code false}.
    1001     * </p>
    1002     *
    1003     * <pre>
    1004     * StringUtils.contains(null, *)    = false
    1005     * StringUtils.contains("", *)      = false
    1006     * StringUtils.contains("abc", 'a') = true
    1007     * StringUtils.contains("abc", 'z') = false
    1008     * </pre>
    1009     *
    1010     * @param seq        the CharSequence to check, may be null
    1011     * @param searchChar the character to find
    1012     * @return true if the CharSequence contains the search character, false if not or {@code null} string input
    1013     * @since 2.0
    1014     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
    1015     */
    1016    public static boolean contains(final CharSequence seq, final int searchChar) {
    1017        if (isEmpty(seq)) {
    1018            return false;
    1019        }
    1020        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
    1021    }
    1022
    1023    /**
    1024     * Tests if the CharSequence contains any character in the given set of characters.
    1025     *
    1026     * <p>
    1027     * A {@code null} CharSequence will return {@code false}. A {@code null} or zero length search array will return {@code false}.
    1028     * </p>
    1029     *
    1030     * <pre>
    1031     * StringUtils.containsAny(null, *)                  = false
    1032     * StringUtils.containsAny("", *)                    = false
    1033     * StringUtils.containsAny(*, null)                  = false
    1034     * StringUtils.containsAny(*, [])                    = false
    1035     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    1036     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    1037     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    1038     * StringUtils.containsAny("aba", ['z'])             = false
    1039     * </pre>
    1040     *
    1041     * @param cs          the CharSequence to check, may be null.
    1042     * @param searchChars the chars to search for, may be null.
    1043     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input.
    1044     * @since 2.4
    1045     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
    1046     */
    1047    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    1048        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1049            return false;
    1050        }
    1051        final int csLength = cs.length();
    1052        final int searchLength = searchChars.length;
    1053        final int csLast = csLength - 1;
    1054        final int searchLast = searchLength - 1;
    1055        for (int i = 0; i < csLength; i++) {
    1056            final char ch = cs.charAt(i);
    1057            for (int j = 0; j < searchLength; j++) {
    1058                if (searchChars[j] == ch) {
    1059                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1060                        return true;
    1061                    }
    1062                }
    1063            }
    1064        }
    1065        return false;
    1066    }
    1067
    1068    /**
    1069     * Tests if the CharSequence contains any character in the given set of characters.
    1070     *
    1071     * <p>
    1072     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return {@code false}.
    1073     * </p>
    1074     *
    1075     * <pre>
    1076     * StringUtils.containsAny(null, *)               = false
    1077     * StringUtils.containsAny("", *)                 = false
    1078     * StringUtils.containsAny(*, null)               = false
    1079     * StringUtils.containsAny(*, "")                 = false
    1080     * StringUtils.containsAny("zzabyycdxx", "za")    = true
    1081     * StringUtils.containsAny("zzabyycdxx", "by")    = true
    1082     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
    1083     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
    1084     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
    1085     * StringUtils.containsAny("aba", "z")            = false
    1086     * </pre>
    1087     *
    1088     * @param cs          the CharSequence to check, may be null.
    1089     * @param searchChars the chars to search for, may be null.
    1090     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input.
    1091     * @since 2.4
    1092     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
    1093     */
    1094    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
    1095        if (searchChars == null) {
    1096            return false;
    1097        }
    1098        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
    1099    }
    1100
    1101    /**
    1102     * Tests if the CharSequence contains any of the CharSequences in the given array.
    1103     *
    1104     * <p>
    1105     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1106     * return {@code false}.
    1107     * </p>
    1108     *
    1109     * <pre>
    1110     * StringUtils.containsAny(null, *)            = false
    1111     * StringUtils.containsAny("", *)              = false
    1112     * StringUtils.containsAny(*, null)            = false
    1113     * StringUtils.containsAny(*, [])              = false
    1114     * StringUtils.containsAny("abcd", "ab", null) = true
    1115     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1116     * StringUtils.containsAny("abc", "d", "abc")  = true
    1117     * </pre>
    1118     *
    1119     * @param cs The CharSequence to check, may be null.
    1120     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1121     *        null as well.
    1122     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise.
    1123     * @since 3.4
    1124     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}
    1125     */
    1126    @Deprecated
    1127    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
    1128        return Strings.CS.containsAny(cs, searchCharSequences);
    1129    }
    1130
    1131    /**
    1132     * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
    1133     *
    1134     * <p>
    1135     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1136     * return {@code false}.
    1137     * </p>
    1138     *
    1139     * <pre>
    1140     * StringUtils.containsAny(null, *)            = false
    1141     * StringUtils.containsAny("", *)              = false
    1142     * StringUtils.containsAny(*, null)            = false
    1143     * StringUtils.containsAny(*, [])              = false
    1144     * StringUtils.containsAny("abcd", "ab", null) = true
    1145     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1146     * StringUtils.containsAny("abc", "d", "abc")  = true
    1147     * StringUtils.containsAny("abc", "D", "ABC")  = true
    1148     * StringUtils.containsAny("ABC", "d", "abc")  = true
    1149     * </pre>
    1150     *
    1151     * @param cs The CharSequence to check, may be null.
    1152     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1153     *        null as well.
    1154     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1155     * @since 3.12.0
    1156     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}
    1157     */
    1158    @Deprecated
    1159    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
    1160        return Strings.CI.containsAny(cs, searchCharSequences);
    1161    }
    1162
    1163    /**
    1164     * Tests if CharSequence contains a search CharSequence irrespective of case, handling {@code null}. Case-insensitivity is defined as by
    1165     * {@link String#equalsIgnoreCase(String)}.
    1166     *
    1167     * <p>
    1168     * A {@code null} CharSequence will return {@code false}.
    1169     *
    1170     * <pre>
    1171     * StringUtils.containsIgnoreCase(null, *)    = false
    1172     * StringUtils.containsIgnoreCase(*, null)    = false
    1173     * StringUtils.containsIgnoreCase("", "")     = true
    1174     * StringUtils.containsIgnoreCase("abc", "")  = true
    1175     * StringUtils.containsIgnoreCase("abc", "a") = true
    1176     * StringUtils.containsIgnoreCase("abc", "z") = false
    1177     * StringUtils.containsIgnoreCase("abc", "A") = true
    1178     * StringUtils.containsIgnoreCase("abc", "Z") = false
    1179     * </pre>
    1180     *
    1181     * @param str       the CharSequence to check, may be null.
    1182     * @param searchStr the CharSequence to find, may be null.
    1183     * @return true if the CharSequence contains the search CharSequence irrespective of case or false if not or {@code null} string input.
    1184     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence).
    1185     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}
    1186     */
    1187    @Deprecated
    1188    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1189        return Strings.CI.contains(str, searchStr);
    1190    }
    1191
    1192    /**
    1193     * Tests that the CharSequence does not contain certain characters.
    1194     *
    1195     * <p>
    1196     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty CharSequence (length()=0)
    1197     * always returns true.
    1198     * </p>
    1199     *
    1200     * <pre>
    1201     * StringUtils.containsNone(null, *)       = true
    1202     * StringUtils.containsNone(*, null)       = true
    1203     * StringUtils.containsNone("", *)         = true
    1204     * StringUtils.containsNone("ab", '')      = true
    1205     * StringUtils.containsNone("abab", 'xyz') = true
    1206     * StringUtils.containsNone("ab1", 'xyz')  = true
    1207     * StringUtils.containsNone("abz", 'xyz')  = false
    1208     * </pre>
    1209     *
    1210     * @param cs          the CharSequence to check, may be null.
    1211     * @param searchChars an array of invalid chars, may be null.
    1212     * @return true if it contains none of the invalid chars, or is null.
    1213     * @since 2.0
    1214     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
    1215     */
    1216    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    1217        if (cs == null || searchChars == null) {
    1218            return true;
    1219        }
    1220        final int csLen = cs.length();
    1221        final int csLast = csLen - 1;
    1222        final int searchLen = searchChars.length;
    1223        final int searchLast = searchLen - 1;
    1224        for (int i = 0; i < csLen; i++) {
    1225            final char ch = cs.charAt(i);
    1226            for (int j = 0; j < searchLen; j++) {
    1227                if (searchChars[j] == ch) {
    1228                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1229                        return false;
    1230                    }
    1231                }
    1232            }
    1233        }
    1234        return true;
    1235    }
    1236
    1237    /**
    1238     * Tests that the CharSequence does not contain certain characters.
    1239     *
    1240     * <p>
    1241     * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty String ("") always
    1242     * returns true.
    1243     * </p>
    1244     *
    1245     * <pre>
    1246     * StringUtils.containsNone(null, *)       = true
    1247     * StringUtils.containsNone(*, null)       = true
    1248     * StringUtils.containsNone("", *)         = true
    1249     * StringUtils.containsNone("ab", "")      = true
    1250     * StringUtils.containsNone("abab", "xyz") = true
    1251     * StringUtils.containsNone("ab1", "xyz")  = true
    1252     * StringUtils.containsNone("abz", "xyz")  = false
    1253     * </pre>
    1254     *
    1255     * @param cs           the CharSequence to check, may be null.
    1256     * @param invalidChars a String of invalid chars, may be null.
    1257     * @return true if it contains none of the invalid chars, or is null.
    1258     * @since 2.0
    1259     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    1260     */
    1261    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
    1262        if (invalidChars == null) {
    1263            return true;
    1264        }
    1265        return containsNone(cs, invalidChars.toCharArray());
    1266    }
    1267
    1268    /**
    1269     * Tests if the CharSequence contains only certain characters.
    1270     *
    1271     * <p>
    1272     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character array will return {@code false}. An empty CharSequence (length()=0)
    1273     * always returns {@code true}.
    1274     * </p>
    1275     *
    1276     * <pre>
    1277     * StringUtils.containsOnly(null, *)       = false
    1278     * StringUtils.containsOnly(*, null)       = false
    1279     * StringUtils.containsOnly("", *)         = true
    1280     * StringUtils.containsOnly("ab", '')      = false
    1281     * StringUtils.containsOnly("abab", 'abc') = true
    1282     * StringUtils.containsOnly("ab1", 'abc')  = false
    1283     * StringUtils.containsOnly("abz", 'abc')  = false
    1284     * </pre>
    1285     *
    1286     * @param cs    the String to check, may be null.
    1287     * @param valid an array of valid chars, may be null.
    1288     * @return true if it only contains valid chars and is non-null.
    1289     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
    1290     */
    1291    public static boolean containsOnly(final CharSequence cs, final char... valid) {
    1292        // All these pre-checks are to maintain API with an older version
    1293        if (valid == null || cs == null) {
    1294            return false;
    1295        }
    1296        if (cs.length() == 0) {
    1297            return true;
    1298        }
    1299        if (valid.length == 0) {
    1300            return false;
    1301        }
    1302        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    1303    }
    1304
    1305    /**
    1306     * Tests if the CharSequence contains only certain characters.
    1307     *
    1308     * <p>
    1309     * A {@code null} CharSequence will return {@code false}. A {@code null} valid character String will return {@code false}. An empty String (length()=0)
    1310     * always returns {@code true}.
    1311     * </p>
    1312     *
    1313     * <pre>
    1314     * StringUtils.containsOnly(null, *)       = false
    1315     * StringUtils.containsOnly(*, null)       = false
    1316     * StringUtils.containsOnly("", *)         = true
    1317     * StringUtils.containsOnly("ab", "")      = false
    1318     * StringUtils.containsOnly("abab", "abc") = true
    1319     * StringUtils.containsOnly("ab1", "abc")  = false
    1320     * StringUtils.containsOnly("abz", "abc")  = false
    1321     * </pre>
    1322     *
    1323     * @param cs         the CharSequence to check, may be null.
    1324     * @param validChars a String of valid chars, may be null.
    1325     * @return true if it only contains valid chars and is non-null.
    1326     * @since 2.0
    1327     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    1328     */
    1329    public static boolean containsOnly(final CharSequence cs, final String validChars) {
    1330        if (cs == null || validChars == null) {
    1331            return false;
    1332        }
    1333        return containsOnly(cs, validChars.toCharArray());
    1334    }
    1335
    1336    /**
    1337     * Tests whether the given CharSequence contains any whitespace characters.
    1338     *
    1339     * <p>
    1340     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    1341     * </p>
    1342     *
    1343     * <pre>
    1344     * StringUtils.containsWhitespace(null)       = false
    1345     * StringUtils.containsWhitespace("")         = false
    1346     * StringUtils.containsWhitespace("ab")       = false
    1347     * StringUtils.containsWhitespace(" ab")      = true
    1348     * StringUtils.containsWhitespace("a b")      = true
    1349     * StringUtils.containsWhitespace("ab ")      = true
    1350     * </pre>
    1351     *
    1352     * @param seq the CharSequence to check (may be {@code null}).
    1353     * @return {@code true} if the CharSequence is not empty and contains at least 1 (breaking) whitespace character.
    1354     * @since 3.0
    1355     */
    1356    public static boolean containsWhitespace(final CharSequence seq) {
    1357        if (isEmpty(seq)) {
    1358            return false;
    1359        }
    1360        final int strLen = seq.length();
    1361        for (int i = 0; i < strLen; i++) {
    1362            if (Character.isWhitespace(seq.charAt(i))) {
    1363                return true;
    1364            }
    1365        }
    1366        return false;
    1367    }
    1368
    1369    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
    1370        for (int i = 0; i < decomposed.length(); i++) {
    1371            final char charAt = decomposed.charAt(i);
    1372            switch (charAt) {
    1373            case '\u0141':
    1374                decomposed.setCharAt(i, 'L');
    1375                break;
    1376            case '\u0142':
    1377                decomposed.setCharAt(i, 'l');
    1378                break;
    1379            // D with stroke
    1380            case '\u0110':
    1381                // LATIN CAPITAL LETTER D WITH STROKE
    1382                decomposed.setCharAt(i, 'D');
    1383                break;
    1384            case '\u0111':
    1385                // LATIN SMALL LETTER D WITH STROKE
    1386                decomposed.setCharAt(i, 'd');
    1387                break;
    1388            // I with bar
    1389            case '\u0197':
    1390                decomposed.setCharAt(i, 'I');
    1391                break;
    1392            case '\u0268':
    1393                decomposed.setCharAt(i, 'i');
    1394                break;
    1395            case '\u1D7B':
    1396                decomposed.setCharAt(i, 'I');
    1397                break;
    1398            case '\u1DA4':
    1399                decomposed.setCharAt(i, 'i');
    1400                break;
    1401            case '\u1DA7':
    1402                decomposed.setCharAt(i, 'I');
    1403                break;
    1404            // U with bar
    1405            case '\u0244':
    1406                // LATIN CAPITAL LETTER U BAR
    1407                decomposed.setCharAt(i, 'U');
    1408                break;
    1409            case '\u0289':
    1410                // LATIN SMALL LETTER U BAR
    1411                decomposed.setCharAt(i, 'u');
    1412                break;
    1413            case '\u1D7E':
    1414                // LATIN SMALL CAPITAL LETTER U WITH STROKE
    1415                decomposed.setCharAt(i, 'U');
    1416                break;
    1417            case '\u1DB6':
    1418                // MODIFIER LETTER SMALL U BAR
    1419                decomposed.setCharAt(i, 'u');
    1420                break;
    1421            // T with stroke
    1422            case '\u0166':
    1423                // LATIN CAPITAL LETTER T WITH STROKE
    1424                decomposed.setCharAt(i, 'T');
    1425                break;
    1426            case '\u0167':
    1427                // LATIN SMALL LETTER T WITH STROKE
    1428                decomposed.setCharAt(i, 't');
    1429                break;
    1430            default:
    1431                break;
    1432            }
    1433        }
    1434    }
    1435
    1436    /**
    1437     * Counts how many times the char appears in the given string.
    1438     *
    1439     * <p>
    1440     * A {@code null} or empty ("") String input returns {@code 0}.
    1441     * </p>
    1442     *
    1443     * <pre>
    1444     * StringUtils.countMatches(null, *)     = 0
    1445     * StringUtils.countMatches("", *)       = 0
    1446     * StringUtils.countMatches("abba", 0)   = 0
    1447     * StringUtils.countMatches("abba", 'a') = 2
    1448     * StringUtils.countMatches("abba", 'b') = 2
    1449     * StringUtils.countMatches("abba", 'x') = 0
    1450     * </pre>
    1451     *
    1452     * @param str the CharSequence to check, may be null.
    1453     * @param ch  the char to count.
    1454     * @return the number of occurrences, 0 if the CharSequence is {@code null}.
    1455     * @since 3.4
    1456     */
    1457    public static int countMatches(final CharSequence str, final char ch) {
    1458        if (isEmpty(str)) {
    1459            return 0;
    1460        }
    1461        int count = 0;
    1462        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
    1463        for (int i = 0; i < str.length(); i++) {
    1464            if (ch == str.charAt(i)) {
    1465                count++;
    1466            }
    1467        }
    1468        return count;
    1469    }
    1470
    1471    /**
    1472     * Counts how many times the substring appears in the larger string. Note that the code only counts non-overlapping matches.
    1473     *
    1474     * <p>
    1475     * A {@code null} or empty ("") String input returns {@code 0}.
    1476     * </p>
    1477     *
    1478     * <pre>
    1479     * StringUtils.countMatches(null, *)        = 0
    1480     * StringUtils.countMatches("", *)          = 0
    1481     * StringUtils.countMatches("abba", null)   = 0
    1482     * StringUtils.countMatches("abba", "")     = 0
    1483     * StringUtils.countMatches("abba", "a")    = 2
    1484     * StringUtils.countMatches("abba", "ab")   = 1
    1485     * StringUtils.countMatches("abba", "xxx")  = 0
    1486     * StringUtils.countMatches("ababa", "aba") = 1
    1487     * </pre>
    1488     *
    1489     * @param str the CharSequence to check, may be null.
    1490     * @param sub the substring to count, may be null.
    1491     * @return the number of occurrences, 0 if either CharSequence is {@code null}.
    1492     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
    1493     */
    1494    public static int countMatches(final CharSequence str, final CharSequence sub) {
    1495        if (isEmpty(str) || isEmpty(sub)) {
    1496            return 0;
    1497        }
    1498        int count = 0;
    1499        int idx = 0;
    1500        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
    1501            count++;
    1502            idx += sub.length();
    1503        }
    1504        return count;
    1505    }
    1506
    1507    /**
    1508     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
    1509     * {@code null}), the value of {@code defaultStr}.
    1510     *
    1511     * <p>
    1512     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    1513     * </p>
    1514     *
    1515     * <pre>
    1516     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
    1517     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
    1518     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
    1519     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
    1520     * StringUtils.defaultIfBlank("", null)      = null
    1521     * </pre>
    1522     *
    1523     * @param <T>        the specific kind of CharSequence.
    1524     * @param str        the CharSequence to check, may be null.
    1525     * @param defaultStr the default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code""}) or
    1526     *                   {@code null}); may be null.
    1527     * @return the passed in CharSequence, or the default.
    1528     * @see StringUtils#defaultString(String, String)
    1529     * @see #isBlank(CharSequence)
    1530     */
    1531    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
    1532        return isBlank(str) ? defaultStr : str;
    1533    }
    1534
    1535    /**
    1536     * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value of {@code defaultStr}.
    1537     *
    1538     * <pre>
    1539     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    1540     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    1541     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
    1542     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    1543     * StringUtils.defaultIfEmpty("", null)      = null
    1544     * </pre>
    1545     *
    1546     * @param <T>        the specific kind of CharSequence.
    1547     * @param str        the CharSequence to check, may be null.
    1548     * @param defaultStr the default CharSequence to return if the input is empty ("") or {@code null}, may be null.
    1549     * @return the passed in CharSequence, or the default.
    1550     * @see StringUtils#defaultString(String, String)
    1551     */
    1552    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
    1553        return isEmpty(str) ? defaultStr : str;
    1554    }
    1555
    1556    /**
    1557     * Returns either the passed in String, or if the String is {@code null}, an empty String ("").
    1558     *
    1559     * <pre>
    1560     * StringUtils.defaultString(null)  = ""
    1561     * StringUtils.defaultString("")    = ""
    1562     * StringUtils.defaultString("bat") = "bat"
    1563     * </pre>
    1564     *
    1565     * @param str the String to check, may be null.
    1566     * @return the passed in String, or the empty String if it was {@code null}.
    1567     * @see Objects#toString(Object, String)
    1568     * @see String#valueOf(Object)
    1569     */
    1570    public static String defaultString(final String str) {
    1571        return Objects.toString(str, EMPTY);
    1572    }
    1573
    1574    /**
    1575     * Returns either the given String, or if the String is {@code null}, {@code nullDefault}.
    1576     *
    1577     * <pre>
    1578     * StringUtils.defaultString(null, "NULL")  = "NULL"
    1579     * StringUtils.defaultString("", "NULL")    = ""
    1580     * StringUtils.defaultString("bat", "NULL") = "bat"
    1581     * </pre>
    1582     * <p>
    1583     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
    1584     * </p>
    1585     *
    1586     * <pre>
    1587     * Objects.toString(null, "NULL")  = "NULL"
    1588     * Objects.toString("", "NULL")    = ""
    1589     * Objects.toString("bat", "NULL") = "bat"
    1590     * </pre>
    1591     *
    1592     * @param str         the String to check, may be null.
    1593     * @param nullDefault the default String to return if the input is {@code null}, may be null.
    1594     * @return the passed in String, or the default if it was {@code null}.
    1595     * @see Objects#toString(Object, String)
    1596     * @see String#valueOf(Object)
    1597     * @deprecated Use {@link Objects#toString(Object, String)}
    1598     */
    1599    @Deprecated
    1600    public static String defaultString(final String str, final String nullDefault) {
    1601        return Objects.toString(str, nullDefault);
    1602    }
    1603
    1604    /**
    1605     * Deletes all whitespaces from a String as defined by {@link Character#isWhitespace(char)}.
    1606     *
    1607     * <pre>
    1608     * StringUtils.deleteWhitespace(null)         = null
    1609     * StringUtils.deleteWhitespace("")           = ""
    1610     * StringUtils.deleteWhitespace("abc")        = "abc"
    1611     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    1612     * </pre>
    1613     *
    1614     * @param str the String to delete whitespace from, may be null.
    1615     * @return the String without whitespaces, {@code null} if null String input.
    1616     */
    1617    public static String deleteWhitespace(final String str) {
    1618        if (isEmpty(str)) {
    1619            return str;
    1620        }
    1621        final int sz = str.length();
    1622        final char[] chs = new char[sz];
    1623        int count = 0;
    1624        for (int i = 0; i < sz; i++) {
    1625            if (!Character.isWhitespace(str.charAt(i))) {
    1626                chs[count++] = str.charAt(i);
    1627            }
    1628        }
    1629        if (count == sz) {
    1630            return str;
    1631        }
    1632        if (count == 0) {
    1633            return EMPTY;
    1634        }
    1635        return new String(chs, 0, count);
    1636    }
    1637
    1638    /**
    1639     * Compares two Strings, and returns the portion where they differ. More precisely, return the remainder of the second String, starting from where it's
    1640     * different from the first. This means that the difference between "abc" and "ab" is the empty String and not "c".
    1641     *
    1642     * <p>
    1643     * For example, {@code difference("i am a machine", "i am a robot") -> "robot"}.
    1644     * </p>
    1645     *
    1646     * <pre>
    1647     * StringUtils.difference(null, null)       = null
    1648     * StringUtils.difference("", "")           = ""
    1649     * StringUtils.difference("", "abc")        = "abc"
    1650     * StringUtils.difference("abc", "")        = ""
    1651     * StringUtils.difference("abc", "abc")     = ""
    1652     * StringUtils.difference("abc", "ab")      = ""
    1653     * StringUtils.difference("ab", "abxyz")    = "xyz"
    1654     * StringUtils.difference("abcde", "abxyz") = "xyz"
    1655     * StringUtils.difference("abcde", "xyz")   = "xyz"
    1656     * </pre>
    1657     *
    1658     * @param str1 the first String, may be null.
    1659     * @param str2 the second String, may be null.
    1660     * @return the portion of str2 where it differs from str1; returns the empty String if they are equal.
    1661     * @see #indexOfDifference(CharSequence,CharSequence)
    1662     * @since 2.0
    1663     */
    1664    public static String difference(final String str1, final String str2) {
    1665        if (str1 == null) {
    1666            return str2;
    1667        }
    1668        if (str2 == null) {
    1669            return str1;
    1670        }
    1671        final int at = indexOfDifference(str1, str2);
    1672        if (at == INDEX_NOT_FOUND) {
    1673            return EMPTY;
    1674        }
    1675        return str2.substring(at);
    1676    }
    1677
    1678    /**
    1679     * Tests if a CharSequence ends with a specified suffix.
    1680     *
    1681     * <p>
    1682     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
    1683     * </p>
    1684     *
    1685     * <pre>
    1686     * StringUtils.endsWith(null, null)      = true
    1687     * StringUtils.endsWith(null, "def")     = false
    1688     * StringUtils.endsWith("abcdef", null)  = false
    1689     * StringUtils.endsWith("abcdef", "def") = true
    1690     * StringUtils.endsWith("ABCDEF", "def") = false
    1691     * StringUtils.endsWith("ABCDEF", "cde") = false
    1692     * StringUtils.endsWith("ABCDEF", "")    = true
    1693     * </pre>
    1694     *
    1695     * @param str    the CharSequence to check, may be null.
    1696     * @param suffix the suffix to find, may be null.
    1697     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or both {@code null}.
    1698     * @see String#endsWith(String)
    1699     * @since 2.4
    1700     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
    1701     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
    1702     */
    1703    @Deprecated
    1704    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
    1705        return Strings.CS.endsWith(str, suffix);
    1706    }
    1707
    1708    /**
    1709     * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
    1710     *
    1711     * <pre>
    1712     * StringUtils.endsWithAny(null, null)                  = false
    1713     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
    1714     * StringUtils.endsWithAny("abcxyz", null)              = false
    1715     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
    1716     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
    1717     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    1718     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
    1719     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
    1720     * </pre>
    1721     *
    1722     * @param sequence      the CharSequence to check, may be null.
    1723     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}.
    1724     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} ends in any
    1725     *         of the provided case-sensitive {@code searchStrings}.
    1726     * @see StringUtils#endsWith(CharSequence, CharSequence)
    1727     * @since 3.0
    1728     * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}
    1729     */
    1730    @Deprecated
    1731    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    1732        return Strings.CS.endsWithAny(sequence, searchStrings);
    1733    }
    1734
    1735    /**
    1736     * Case-insensitive check if a CharSequence ends with a specified suffix.
    1737     *
    1738     * <p>
    1739     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
    1740     * </p>
    1741     *
    1742     * <pre>
    1743     * StringUtils.endsWithIgnoreCase(null, null)      = true
    1744     * StringUtils.endsWithIgnoreCase(null, "def")     = false
    1745     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    1746     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    1747     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    1748     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    1749     * </pre>
    1750     *
    1751     * @param str    the CharSequence to check, may be null
    1752     * @param suffix the suffix to find, may be null
    1753     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or both {@code null}
    1754     * @see String#endsWith(String)
    1755     * @since 2.4
    1756     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
    1757     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CI.endsWith(CharSequence, CharSequence)}
    1758     */
    1759    @Deprecated
    1760    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
    1761        return Strings.CI.endsWith(str, suffix);
    1762    }
    1763
    1764    /**
    1765     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
    1766     *
    1767     * <p>
    1768     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is <strong>case-sensitive</strong>.
    1769     * </p>
    1770     *
    1771     * <pre>
    1772     * StringUtils.equals(null, null)   = true
    1773     * StringUtils.equals(null, "abc")  = false
    1774     * StringUtils.equals("abc", null)  = false
    1775     * StringUtils.equals("abc", "abc") = true
    1776     * StringUtils.equals("abc", "ABC") = false
    1777     * </pre>
    1778     *
    1779     * @param cs1 the first CharSequence, may be {@code null}.
    1780     * @param cs2 the second CharSequence, may be {@code null}.
    1781     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}.
    1782     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    1783     * @see Object#equals(Object)
    1784     * @see #equalsIgnoreCase(CharSequence, CharSequence)
    1785     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}
    1786     */
    1787    @Deprecated
    1788    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
    1789        return Strings.CS.equals(cs1, cs2);
    1790    }
    1791
    1792    /**
    1793     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, returning {@code true} if the {@code string} is equal to any of the
    1794     * {@code searchStrings}.
    1795     *
    1796     * <pre>
    1797     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
    1798     * StringUtils.equalsAny(null, null, null)    = true
    1799     * StringUtils.equalsAny(null, "abc", "def")  = false
    1800     * StringUtils.equalsAny("abc", null, "def")  = false
    1801     * StringUtils.equalsAny("abc", "abc", "def") = true
    1802     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
    1803     * </pre>
    1804     *
    1805     * @param string        to compare, may be {@code null}.
    1806     * @param searchStrings a vararg of strings, may be {@code null}.
    1807     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; {@code false} if {@code searchStrings} is
    1808     *         null or contains no matches.
    1809     * @since 3.5
    1810     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}
    1811     */
    1812    @Deprecated
    1813    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
    1814        return Strings.CS.equalsAny(string, searchStrings);
    1815    }
    1816
    1817    /**
    1818     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1819     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
    1820     *
    1821     * <pre>
    1822     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
    1823     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
    1824     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
    1825     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
    1826     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
    1827     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
    1828     * </pre>
    1829     *
    1830     * @param string to compare, may be {@code null}.
    1831     * @param searchStrings a vararg of strings, may be {@code null}.
    1832     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
    1833     * {@code false} if {@code searchStrings} is null or contains no matches.
    1834     * @since 3.5
    1835     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI-.equalsAny(CharSequence, CharSequence...)}
    1836     */
    1837    @Deprecated
    1838    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
    1839        return Strings.CI.equalsAny(string, searchStrings);
    1840    }
    1841
    1842    /**
    1843     * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters, ignoring case.
    1844     *
    1845     * <p>
    1846     * {@code null}s are handled without exceptions. Two {@code null} references are considered equal. The comparison is <strong>case insensitive</strong>.
    1847     * </p>
    1848     *
    1849     * <pre>
    1850     * StringUtils.equalsIgnoreCase(null, null)   = true
    1851     * StringUtils.equalsIgnoreCase(null, "abc")  = false
    1852     * StringUtils.equalsIgnoreCase("abc", null)  = false
    1853     * StringUtils.equalsIgnoreCase("abc", "abc") = true
    1854     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    1855     * </pre>
    1856     *
    1857     * @param cs1 the first CharSequence, may be {@code null}.
    1858     * @param cs2 the second CharSequence, may be {@code null}.
    1859     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}.
    1860     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
    1861     * @see #equals(CharSequence, CharSequence)
    1862     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}
    1863     */
    1864    @Deprecated
    1865    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
    1866        return Strings.CI.equals(cs1, cs2);
    1867    }
    1868
    1869    /**
    1870     * Returns the first value in the array which is not empty (""), {@code null} or whitespace only.
    1871     *
    1872     * <p>
    1873     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    1874     * </p>
    1875     *
    1876     * <p>
    1877     * If all values are blank or the array is {@code null} or empty then {@code null} is returned.
    1878     * </p>
    1879     *
    1880     * <pre>
    1881     * StringUtils.firstNonBlank(null, null, null)     = null
    1882     * StringUtils.firstNonBlank(null, "", " ")        = null
    1883     * StringUtils.firstNonBlank("abc")                = "abc"
    1884     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
    1885     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
    1886     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
    1887     * StringUtils.firstNonBlank()                     = null
    1888     * </pre>
    1889     *
    1890     * @param <T>    the specific kind of CharSequence.
    1891     * @param values the values to test, may be {@code null} or empty.
    1892     * @return the first value from {@code values} which is not blank, or {@code null} if there are no non-blank values.
    1893     * @since 3.8
    1894     */
    1895    @SafeVarargs
    1896    public static <T extends CharSequence> T firstNonBlank(final T... values) {
    1897        if (values != null) {
    1898            for (final T val : values) {
    1899                if (isNotBlank(val)) {
    1900                    return val;
    1901                }
    1902            }
    1903        }
    1904        return null;
    1905    }
    1906
    1907    /**
    1908     * Returns the first value in the array which is not empty.
    1909     *
    1910     * <p>
    1911     * If all values are empty or the array is {@code null} or empty then {@code null} is returned.
    1912     * </p>
    1913     *
    1914     * <pre>
    1915     * StringUtils.firstNonEmpty(null, null, null)   = null
    1916     * StringUtils.firstNonEmpty(null, null, "")     = null
    1917     * StringUtils.firstNonEmpty(null, "", " ")      = " "
    1918     * StringUtils.firstNonEmpty("abc")              = "abc"
    1919     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
    1920     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
    1921     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
    1922     * StringUtils.firstNonEmpty()                   = null
    1923     * </pre>
    1924     *
    1925     * @param <T>    the specific kind of CharSequence.
    1926     * @param values the values to test, may be {@code null} or empty.
    1927     * @return the first value from {@code values} which is not empty, or {@code null} if there are no non-empty values.
    1928     * @since 3.8
    1929     */
    1930    @SafeVarargs
    1931    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
    1932        if (values != null) {
    1933            for (final T val : values) {
    1934                if (isNotEmpty(val)) {
    1935                    return val;
    1936                }
    1937            }
    1938        }
    1939        return null;
    1940    }
    1941
    1942    /**
    1943     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
    1944     *
    1945     * @param string input string.
    1946     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
    1947     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
    1948     * @see String#getBytes(Charset)
    1949     * @since 3.10
    1950     */
    1951    public static byte[] getBytes(final String string, final Charset charset) {
    1952        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
    1953    }
    1954
    1955    /**
    1956     * Calls {@link String#getBytes(String)} in a null-safe manner.
    1957     *
    1958     * @param string input string.
    1959     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
    1960     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
    1961     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
    1962     * @see String#getBytes(String)
    1963     * @since 3.10
    1964     */
    1965    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
    1966        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
    1967    }
    1968
    1969    /**
    1970     * Compares all Strings in an array and returns the initial sequence of characters that is common to all of them.
    1971     *
    1972     * <p>
    1973     * For example, {@code getCommonPrefix("i am a machine", "i am a robot") -&gt; "i am a "}
    1974     * </p>
    1975     *
    1976     * <pre>
    1977     * StringUtils.getCommonPrefix(null)                             = ""
    1978     * StringUtils.getCommonPrefix(new String[] {})                  = ""
    1979     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
    1980     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
    1981     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
    1982     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
    1983     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    1984     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    1985     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
    1986     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
    1987     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
    1988     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
    1989     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
    1990     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
    1991     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
    1992     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
    1993     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    1994     * </pre>
    1995     *
    1996     * @param strs array of String objects, entries may be null.
    1997     * @return the initial sequence of characters that are common to all Strings in the array; empty String if the array is null, the elements are all null or
    1998     *         if there is no common prefix.
    1999     * @since 2.4
    2000     */
    2001    public static String getCommonPrefix(final String... strs) {
    2002        if (ArrayUtils.isEmpty(strs)) {
    2003            return EMPTY;
    2004        }
    2005        final int smallestIndexOfDiff = indexOfDifference(strs);
    2006        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    2007            // all strings were identical
    2008            if (strs[0] == null) {
    2009                return EMPTY;
    2010            }
    2011            return strs[0];
    2012        }
    2013        if (smallestIndexOfDiff == 0) {
    2014            // there were no common initial characters
    2015            return EMPTY;
    2016        }
    2017        // we found a common initial character sequence
    2018        return strs[0].substring(0, smallestIndexOfDiff);
    2019    }
    2020
    2021    /**
    2022     * Checks if a String {@code str} contains Unicode digits, if yes then concatenate all the digits in {@code str} and return it as a String.
    2023     *
    2024     * <p>
    2025     * An empty ("") String will be returned if no digits found in {@code str}.
    2026     * </p>
    2027     *
    2028     * <pre>
    2029     * StringUtils.getDigits(null)                 = null
    2030     * StringUtils.getDigits("")                   = ""
    2031     * StringUtils.getDigits("abc")                = ""
    2032     * StringUtils.getDigits("1000$")              = "1000"
    2033     * StringUtils.getDigits("1123~45")            = "112345"
    2034     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
    2035     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
    2036     * </pre>
    2037     *
    2038     * @param str the String to extract digits from, may be null.
    2039     * @return String with only digits, or an empty ("") String if no digits found, or {@code null} String if {@code str} is null.
    2040     * @since 3.6
    2041     */
    2042    public static String getDigits(final String str) {
    2043        if (isEmpty(str)) {
    2044            return str;
    2045        }
    2046        final int sz = str.length();
    2047        final StringBuilder strDigits = new StringBuilder(sz);
    2048        for (int i = 0; i < sz; i++) {
    2049            final char tempChar = str.charAt(i);
    2050            if (Character.isDigit(tempChar)) {
    2051                strDigits.append(tempChar);
    2052            }
    2053        }
    2054        return strDigits.toString();
    2055    }
    2056
    2057    /**
    2058     * Gets the Fuzzy Distance which indicates the similarity score between two Strings.
    2059     *
    2060     * <p>
    2061     * This string matching algorithm is similar to the algorithms of editors such as Sublime Text, TextMate, Atom and others. One point is given for every
    2062     * matched character. Subsequent matches yield two bonus points. A higher score indicates a higher similarity.
    2063     * </p>
    2064     *
    2065     * <pre>
    2066     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
    2067     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
    2068     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
    2069     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
    2070     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
    2071     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
    2072     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
    2073     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
    2074     * </pre>
    2075     *
    2076     * @param term   a full term that should be matched against, must not be null.
    2077     * @param query  the query that will be matched against a term, must not be null.
    2078     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize both Strings to lower case.
    2079     * @return result score.
    2080     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}.
    2081     * @since 3.4
    2082     * @deprecated As of 3.6, use Apache Commons Text
    2083     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
    2084     *             FuzzyScore</a> instead
    2085     */
    2086    @Deprecated
    2087    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
    2088        if (term == null || query == null) {
    2089            throw new IllegalArgumentException("Strings must not be null");
    2090        }
    2091        if (locale == null) {
    2092            throw new IllegalArgumentException("Locale must not be null");
    2093        }
    2094        // fuzzy logic is case-insensitive. We normalize the Strings to lower
    2095        // case right from the start. Turning characters to lower case
    2096        // via Character.toLowerCase(char) is unfortunately insufficient
    2097        // as it does not accept a locale.
    2098        final String termLowerCase = term.toString().toLowerCase(locale);
    2099        final String queryLowerCase = query.toString().toLowerCase(locale);
    2100        // the resulting score
    2101        int score = 0;
    2102        // the position in the term which will be scanned next for potential
    2103        // query character matches
    2104        int termIndex = 0;
    2105        // index of the previously matched character in the term
    2106        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
    2107        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
    2108            final char queryChar = queryLowerCase.charAt(queryIndex);
    2109            boolean termCharacterMatchFound = false;
    2110            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
    2111                final char termChar = termLowerCase.charAt(termIndex);
    2112                if (queryChar == termChar) {
    2113                    // simple character matches result in one point
    2114                    score++;
    2115                    // subsequent character matches further improve
    2116                    // the score.
    2117                    if (previousMatchingCharacterIndex + 1 == termIndex) {
    2118                        score += 2;
    2119                    }
    2120                    previousMatchingCharacterIndex = termIndex;
    2121                    // we can leave the nested loop. Every character in the
    2122                    // query can match at most one character in the term.
    2123                    termCharacterMatchFound = true;
    2124                }
    2125            }
    2126        }
    2127        return score;
    2128    }
    2129
    2130    /**
    2131     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
    2132     * {@code null}), the value supplied by {@code defaultStrSupplier}.
    2133     *
    2134     * <p>
    2135     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    2136     * </p>
    2137     *
    2138     * <p>
    2139     * Caller responsible for thread-safety and exception handling of default value supplier
    2140     * </p>
    2141     *
    2142     * <pre>
    2143     * {@code
    2144     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
    2145     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
    2146     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
    2147     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
    2148     * StringUtils.getIfBlank("", () -> null)       = null
    2149     * StringUtils.getIfBlank("", null)             = null
    2150     * }</pre>
    2151     *
    2152     * @param <T>             the specific kind of CharSequence.
    2153     * @param str             the CharSequence to check, may be null.
    2154     * @param defaultSupplier the supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
    2155     *                        ({@code ""}) or {@code null}); may be null.
    2156     * @return the passed in CharSequence, or the default
    2157     * @see StringUtils#defaultString(String, String)
    2158     * @see #isBlank(CharSequence)
    2159     * @since 3.10
    2160     */
    2161    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
    2162        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
    2163    }
    2164
    2165    /**
    2166     * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
    2167     *
    2168     * <p>
    2169     * Caller responsible for thread-safety and exception handling of default value supplier
    2170     * </p>
    2171     *
    2172     * <pre>
    2173     * {@code
    2174     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
    2175     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
    2176     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
    2177     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
    2178     * StringUtils.getIfEmpty("", () -> null)        = null
    2179     * StringUtils.getIfEmpty("", null)              = null
    2180     * }
    2181     * </pre>
    2182     *
    2183     * @param <T>             the specific kind of CharSequence.
    2184     * @param str             the CharSequence to check, may be null.
    2185     * @param defaultSupplier the supplier of default CharSequence to return if the input is empty ("") or {@code null}, may be null.
    2186     * @return the passed in CharSequence, or the default.
    2187     * @see StringUtils#defaultString(String, String)
    2188     * @since 3.10
    2189     */
    2190    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
    2191        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
    2192    }
    2193
    2194    /**
    2195     * Gets the Jaro Winkler Distance which indicates the similarity score between two Strings.
    2196     *
    2197     * <p>
    2198     * The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. Winkler increased this measure for
    2199     * matching initial characters.
    2200     * </p>
    2201     *
    2202     * <p>
    2203     * This implementation is based on the Jaro Winkler similarity algorithm from
    2204     * <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
    2205     * </p>
    2206     *
    2207     * <pre>
    2208     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
    2209     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
    2210     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
    2211     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
    2212     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
    2213     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
    2214     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
    2215     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
    2216     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
    2217     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
    2218     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
    2219     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
    2220     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
    2221     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
    2222     * </pre>
    2223     *
    2224     * @param first  the first String, must not be null.
    2225     * @param second the second String, must not be null.
    2226     * @return result distance.
    2227     * @throws IllegalArgumentException if either String input {@code null}.
    2228     * @since 3.3
    2229     * @deprecated As of 3.6, use Apache Commons Text
    2230     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
    2231     *             JaroWinklerDistance</a> instead
    2232     */
    2233    @Deprecated
    2234    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
    2235        final double DEFAULT_SCALING_FACTOR = 0.1;
    2236
    2237        if (first == null || second == null) {
    2238            throw new IllegalArgumentException("Strings must not be null");
    2239        }
    2240
    2241        final int[] mtp = matches(first, second);
    2242        final double m = mtp[0];
    2243        if (m == 0) {
    2244            return 0D;
    2245        }
    2246        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
    2247        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
    2248        return Math.round(jw * 100.0D) / 100.0D;
    2249    }
    2250
    2251    /**
    2252     * Gets the Levenshtein distance between two Strings.
    2253     *
    2254     * <p>
    2255     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
    2256     * substitution).
    2257     * </p>
    2258     *
    2259     * <p>
    2260     * The implementation uses a single-dimensional array of length s.length() + 1. See
    2261     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
    2262     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.
    2263     * </p>
    2264     *
    2265     * <pre>
    2266     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    2267     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    2268     * StringUtils.getLevenshteinDistance("", "")              = 0
    2269     * StringUtils.getLevenshteinDistance("", "a")             = 1
    2270     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    2271     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    2272     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    2273     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    2274     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    2275     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    2276     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    2277     * </pre>
    2278     *
    2279     * @param s the first String, must not be null.
    2280     * @param t the second String, must not be null.
    2281     * @return result distance.
    2282     * @throws IllegalArgumentException if either String input {@code null}.
    2283     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to getLevenshteinDistance(CharSequence, CharSequence)
    2284     * @deprecated As of 3.6, use Apache Commons Text
    2285     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2286     *             LevenshteinDistance</a> instead
    2287     */
    2288    @Deprecated
    2289    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    2290        if (s == null || t == null) {
    2291            throw new IllegalArgumentException("Strings must not be null");
    2292        }
    2293
    2294        int n = s.length();
    2295        int m = t.length();
    2296
    2297        if (n == 0) {
    2298            return m;
    2299        }
    2300        if (m == 0) {
    2301            return n;
    2302        }
    2303
    2304        if (n > m) {
    2305            // swap the input strings to consume less memory
    2306            final CharSequence tmp = s;
    2307            s = t;
    2308            t = tmp;
    2309            n = m;
    2310            m = t.length();
    2311        }
    2312
    2313        final int[] p = new int[n + 1];
    2314        // indexes into strings s and t
    2315        int i; // iterates through s
    2316        int j; // iterates through t
    2317        int upperleft;
    2318        int upper;
    2319
    2320        char jOfT; // jth character of t
    2321        int cost;
    2322
    2323        for (i = 0; i <= n; i++) {
    2324            p[i] = i;
    2325        }
    2326
    2327        for (j = 1; j <= m; j++) {
    2328            upperleft = p[0];
    2329            jOfT = t.charAt(j - 1);
    2330            p[0] = j;
    2331
    2332            for (i = 1; i <= n; i++) {
    2333                upper = p[i];
    2334                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
    2335                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    2336                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
    2337                upperleft = upper;
    2338            }
    2339        }
    2340
    2341        return p[n];
    2342    }
    2343
    2344    /**
    2345     * Gets the Levenshtein distance between two Strings if it's less than or equal to a given threshold.
    2346     *
    2347     * <p>
    2348     * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
    2349     * substitution).
    2350     * </p>
    2351     *
    2352     * <p>
    2353     * This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield and Chas Emerick's implementation of the Levenshtein distance
    2354     * algorithm from <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a>
    2355     * </p>
    2356     *
    2357     * <pre>
    2358     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
    2359     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
    2360     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
    2361     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
    2362     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
    2363     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
    2364     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
    2365     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
    2366     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
    2367     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
    2368     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
    2369     * </pre>
    2370     *
    2371     * @param s         the first String, must not be null.
    2372     * @param t         the second String, must not be null.
    2373     * @param threshold the target threshold, must not be negative.
    2374     * @return result distance, or {@code -1} if the distance would be greater than the threshold.
    2375     * @throws IllegalArgumentException if either String input {@code null} or negative threshold.
    2376     * @deprecated As of 3.6, use Apache Commons Text
    2377     *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2378     *             LevenshteinDistance</a> instead
    2379     */
    2380    @Deprecated
    2381    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
    2382        if (s == null || t == null) {
    2383            throw new IllegalArgumentException("Strings must not be null");
    2384        }
    2385        if (threshold < 0) {
    2386            throw new IllegalArgumentException("Threshold must not be negative");
    2387        }
    2388
    2389        /*
    2390        This implementation only computes the distance if it's less than or equal to the
    2391        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    2392        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    2393        computing a diagonal stripe of width 2k + 1 of the cost table.
    2394        It is also possible to use this to compute the unbounded Levenshtein distance by starting
    2395        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    2396        d is the distance.
    2397
    2398        One subtlety comes from needing to ignore entries on the border of our stripe
    2399        eg.
    2400        p[] = |#|#|#|*
    2401        d[] =  *|#|#|#|
    2402        We must ignore the entry to the left of the leftmost member
    2403        We must ignore the entry above the rightmost member
    2404
    2405        Another subtlety comes from our stripe running off the matrix if the strings aren't
    2406        of the same size.  Since string s is always swapped to be the shorter of the two,
    2407        the stripe will always run off to the upper right instead of the lower left of the matrix.
    2408
    2409        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    2410        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
    2411
    2412           1 2 3 4 5
    2413        1 |#|#| | | |
    2414        2 |#|#|#| | |
    2415        3 | |#|#|#| |
    2416        4 | | |#|#|#|
    2417        5 | | | |#|#|
    2418        6 | | | | |#|
    2419        7 | | | | | |
    2420
    2421        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    2422        into one of length 7 in edit distance of 1.
    2423
    2424        Additionally, this implementation decreases memory usage by using two
    2425        single-dimensional arrays and swapping them back and forth instead of allocating
    2426        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    2427        when it's detected that the stripe has run off the matrix and initially filling the arrays with
    2428        large values so that entries we don't compute are ignored.
    2429
    2430        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
    2431         */
    2432
    2433        int n = s.length(); // length of s
    2434        int m = t.length(); // length of t
    2435
    2436        // if one string is empty, the edit distance is necessarily the length of the other
    2437        if (n == 0) {
    2438            return m <= threshold ? m : -1;
    2439        }
    2440        if (m == 0) {
    2441            return n <= threshold ? n : -1;
    2442        }
    2443        if (Math.abs(n - m) > threshold) {
    2444            // no need to calculate the distance if the length difference is greater than the threshold
    2445            return -1;
    2446        }
    2447
    2448        if (n > m) {
    2449            // swap the two strings to consume less memory
    2450            final CharSequence tmp = s;
    2451            s = t;
    2452            t = tmp;
    2453            n = m;
    2454            m = t.length();
    2455        }
    2456
    2457        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
    2458        int[] d = new int[n + 1]; // cost array, horizontally
    2459        int[] tmp; // placeholder to assist in swapping p and d
    2460
    2461        // fill in starting table values
    2462        final int boundary = Math.min(n, threshold) + 1;
    2463        for (int i = 0; i < boundary; i++) {
    2464            p[i] = i;
    2465        }
    2466        // these fills ensure that the value above the rightmost entry of our
    2467        // stripe will be ignored in following loop iterations
    2468        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    2469        Arrays.fill(d, Integer.MAX_VALUE);
    2470
    2471        // iterates through t
    2472        for (int j = 1; j <= m; j++) {
    2473            final char jOfT = t.charAt(j - 1); // jth character of t
    2474            d[0] = j;
    2475
    2476            // compute stripe indices, constrain to array size
    2477            final int min = Math.max(1, j - threshold);
    2478            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
    2479
    2480            // the stripe may lead off of the table if s and t are of different sizes
    2481            if (min > max) {
    2482                return -1;
    2483            }
    2484
    2485            // ignore entry left of leftmost
    2486            if (min > 1) {
    2487                d[min - 1] = Integer.MAX_VALUE;
    2488            }
    2489
    2490            // iterates through [min, max] in s
    2491            for (int i = min; i <= max; i++) {
    2492                if (s.charAt(i - 1) == jOfT) {
    2493                    // diagonally left and up
    2494                    d[i] = p[i - 1];
    2495                } else {
    2496                    // 1 + minimum of cell to the left, to the top, diagonally left and up
    2497                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
    2498                }
    2499            }
    2500
    2501            // copy current distance counts to 'previous row' distance counts
    2502            tmp = p;
    2503            p = d;
    2504            d = tmp;
    2505        }
    2506
    2507        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    2508        // distance
    2509        if (p[n] <= threshold) {
    2510            return p[n];
    2511        }
    2512        return -1;
    2513    }
    2514
    2515    /**
    2516     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
    2517     *
    2518     * <p>
    2519     * A {@code null} CharSequence will return {@code -1}.
    2520     * </p>
    2521     *
    2522     * <pre>
    2523     * StringUtils.indexOf(null, *)          = -1
    2524     * StringUtils.indexOf(*, null)          = -1
    2525     * StringUtils.indexOf("", "")           = 0
    2526     * StringUtils.indexOf("", *)            = -1 (except when * = "")
    2527     * StringUtils.indexOf("aabaabaa", "a")  = 0
    2528     * StringUtils.indexOf("aabaabaa", "b")  = 2
    2529     * StringUtils.indexOf("aabaabaa", "ab") = 1
    2530     * StringUtils.indexOf("aabaabaa", "")   = 0
    2531     * </pre>
    2532     *
    2533     * @param seq       the CharSequence to check, may be null.
    2534     * @param searchSeq the CharSequence to find, may be null.
    2535     * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
    2536     * @since 2.0
    2537     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
    2538     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}
    2539     */
    2540    @Deprecated
    2541    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
    2542        return Strings.CS.indexOf(seq, searchSeq);
    2543    }
    2544
    2545    /**
    2546     * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
    2547     *
    2548     * <p>
    2549     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
    2550     * start position greater than the string length only matches an empty search CharSequence.
    2551     * </p>
    2552     *
    2553     * <pre>
    2554     * StringUtils.indexOf(null, *, *)          = -1
    2555     * StringUtils.indexOf(*, null, *)          = -1
    2556     * StringUtils.indexOf("", "", 0)           = 0
    2557     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    2558     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    2559     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    2560     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    2561     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    2562     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    2563     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    2564     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    2565     * StringUtils.indexOf("abc", "", 9)        = 3
    2566     * </pre>
    2567     *
    2568     * @param seq       the CharSequence to check, may be null.
    2569     * @param searchSeq the CharSequence to find, may be null.
    2570     * @param startPos  the start position, negative treated as zero.
    2571     * @return the first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
    2572     * @since 2.0
    2573     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
    2574     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}
    2575     */
    2576    @Deprecated
    2577    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    2578        return Strings.CS.indexOf(seq, searchSeq, startPos);
    2579    }
    2580
    2581    /**
    2582     * Returns the index within {@code seq} of the first occurrence of the specified character. If a character with value {@code searchChar} occurs in the
    2583     * character sequence represented by {@code seq} {@link CharSequence} object, then the index (in Unicode code units) of the first such occurrence is
    2584     * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this is the smallest value <em>k</em> such that:
    2585     *
    2586     * <pre>
    2587     * this.charAt(<em>k</em>) == searchChar
    2588     * </pre>
    2589     *
    2590     * <p>
    2591     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
    2592     * </p>
    2593     *
    2594     * <pre>
    2595     * this.codePointAt(<em>k</em>) == searchChar
    2596     * </pre>
    2597     *
    2598     * <p>
    2599     * is true. In either case, if no such character occurs in {@code seq}, then {@code INDEX_NOT_FOUND (-1)} is returned.
    2600     * </p>
    2601     *
    2602     * <p>
    2603     * Furthermore, a {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
    2604     * </p>
    2605     *
    2606     * <pre>
    2607     * StringUtils.indexOf(null, *)         = -1
    2608     * StringUtils.indexOf("", *)           = -1
    2609     * StringUtils.indexOf("aabaabaa", 'a') = 0
    2610     * StringUtils.indexOf("aabaabaa", 'b') = 2
    2611     * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
    2612     * </pre>
    2613     *
    2614     * @param seq        the CharSequence to check, may be null.
    2615     * @param searchChar the character to find.
    2616     * @return the first index of the search character, -1 if no match or {@code null} string input.
    2617     * @since 2.0
    2618     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
    2619     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2620     */
    2621    public static int indexOf(final CharSequence seq, final int searchChar) {
    2622        if (isEmpty(seq)) {
    2623            return INDEX_NOT_FOUND;
    2624        }
    2625        return CharSequenceUtils.indexOf(seq, searchChar, 0);
    2626    }
    2627
    2628    /**
    2629     * Returns the index within {@code seq} of the first occurrence of the specified character, starting the search at the specified index.
    2630     * <p>
    2631     * If a character with value {@code searchChar} occurs in the character sequence represented by the {@code seq} {@link CharSequence} object at an index no
    2632     * smaller than {@code startPos}, then the index of the first such occurrence is returned. For values of {@code searchChar} in the range from 0 to 0xFFFF
    2633     * (inclusive), this is the smallest value <em>k</em> such that:
    2634     * </p>
    2635     *
    2636     * <pre>
    2637     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
    2638     * </pre>
    2639     *
    2640     * <p>
    2641     * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
    2642     * </p>
    2643     *
    2644     * <pre>
    2645     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
    2646     * </pre>
    2647     *
    2648     * <p>
    2649     * is true. In either case, if no such character occurs in {@code seq} at or after position {@code startPos}, then {@code -1} is returned.
    2650     * </p>
    2651     *
    2652     * <p>
    2653     * There is no restriction on the value of {@code startPos}. If it is negative, it has the same effect as if it were zero: this entire string may be
    2654     * searched. If it is greater than the length of this string, it has the same effect as if it were equal to the length of this string:
    2655     * {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
    2656     * </p>
    2657     * <p>
    2658     * All indices are specified in {@code char} values (Unicode code units).
    2659     *
    2660     * <pre>
    2661     * StringUtils.indexOf(null, *, *)          = -1
    2662     * StringUtils.indexOf("", *, *)            = -1
    2663     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    2664     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    2665     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    2666     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    2667     * </pre>
    2668     *
    2669     * @param seq        the CharSequence to check, may be null.
    2670     * @param searchChar the character to find.
    2671     * @param startPos   the start position, negative treated as zero.
    2672     * @return the first index of the search character (always &ge; startPos), -1 if no match or {@code null} string input.
    2673     * @since 2.0
    2674     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
    2675     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2676     */
    2677    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
    2678        if (isEmpty(seq)) {
    2679            return INDEX_NOT_FOUND;
    2680        }
    2681        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
    2682    }
    2683
    2684    /**
    2685     * Search a CharSequence to find the first index of any character in the given set of characters.
    2686     *
    2687     * <p>
    2688     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
    2689     * </p>
    2690     *
    2691     * <pre>
    2692     * StringUtils.indexOfAny(null, *)                  = -1
    2693     * StringUtils.indexOfAny("", *)                    = -1
    2694     * StringUtils.indexOfAny(*, null)                  = -1
    2695     * StringUtils.indexOfAny(*, [])                    = -1
    2696     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
    2697     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
    2698     * StringUtils.indexOfAny("aba", ['z'])             = -1
    2699     * </pre>
    2700     *
    2701     * @param cs          the CharSequence to check, may be null.
    2702     * @param searchChars the chars to search for, may be null.
    2703     * @return the index of any of the chars, -1 if no match or null input.
    2704     * @since 2.0
    2705     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2706     */
    2707    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    2708        return indexOfAny(cs, 0, searchChars);
    2709    }
    2710
    2711    /**
    2712     * Find the first index of any of a set of potential substrings.
    2713     *
    2714     * <p>
    2715     * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}. A {@code null} search array entry
    2716     * will be ignored, but a search array containing "" will return {@code 0} if {@code str} is not null. This method uses {@link String#indexOf(String)} if
    2717     * possible.
    2718     * </p>
    2719     *
    2720     * <pre>
    2721     * StringUtils.indexOfAny(null, *)                      = -1
    2722     * StringUtils.indexOfAny(*, null)                      = -1
    2723     * StringUtils.indexOfAny(*, [])                        = -1
    2724     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
    2725     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
    2726     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
    2727     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
    2728     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
    2729     * StringUtils.indexOfAny("", [""])                     = 0
    2730     * StringUtils.indexOfAny("", ["a"])                    = -1
    2731     * </pre>
    2732     *
    2733     * @param str        the CharSequence to check, may be null.
    2734     * @param searchStrs the CharSequences to search for, may be null.
    2735     * @return the first index of any of the searchStrs in str, -1 if no match.
    2736     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
    2737     */
    2738    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2739        if (str == null || searchStrs == null) {
    2740            return INDEX_NOT_FOUND;
    2741        }
    2742        // String's can't have a MAX_VALUEth index.
    2743        int ret = Integer.MAX_VALUE;
    2744        int tmp;
    2745        for (final CharSequence search : searchStrs) {
    2746            if (search == null) {
    2747                continue;
    2748            }
    2749            tmp = CharSequenceUtils.indexOf(str, search, 0);
    2750            if (tmp == INDEX_NOT_FOUND) {
    2751                continue;
    2752            }
    2753            if (tmp < ret) {
    2754                ret = tmp;
    2755            }
    2756        }
    2757        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
    2758    }
    2759
    2760    /**
    2761     * Search a CharSequence to find the first index of any character in the given set of characters.
    2762     *
    2763     * <p>
    2764     * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
    2765     * </p>
    2766     * <p>
    2767     * The following is the same as {@code indexOfAny(cs, 0, searchChars)}.
    2768     * </p>
    2769     * <pre>
    2770     * StringUtils.indexOfAny(null, 0, *)                  = -1
    2771     * StringUtils.indexOfAny("", 0, *)                    = -1
    2772     * StringUtils.indexOfAny(*, 0, null)                  = -1
    2773     * StringUtils.indexOfAny(*, 0, [])                    = -1
    2774     * StringUtils.indexOfAny("zzabyycdxx", 0, ['z', 'a']) = 0
    2775     * StringUtils.indexOfAny("zzabyycdxx", 0, ['b', 'y']) = 3
    2776     * StringUtils.indexOfAny("aba", 0, ['z'])             = -1
    2777     * </pre>
    2778     *
    2779     * @param cs          the CharSequence to check, may be null.
    2780     * @param csStart Start searching the input {@code cs} at this index.
    2781     * @param searchChars the chars to search for, may be null.
    2782     * @return the index of any of the chars, -1 if no match or null input.
    2783     * @since 2.0
    2784     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2785     */
    2786    public static int indexOfAny(final CharSequence cs, final int csStart, final char... searchChars) {
    2787        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2788            return INDEX_NOT_FOUND;
    2789        }
    2790        final int csLen = cs.length();
    2791        final int csLast = csLen - 1;
    2792        final int searchLen = searchChars.length;
    2793        final int searchLast = searchLen - 1;
    2794        for (int i = csStart; i < csLen; i++) {
    2795            final char ch = cs.charAt(i);
    2796            for (int j = 0; j < searchLen; j++) {
    2797                if (searchChars[j] == ch) {
    2798                    // ch is a supplementary character
    2799                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch) || searchChars[j + 1] == cs.charAt(i + 1)) {
    2800                        return i;
    2801                    }
    2802                }
    2803            }
    2804        }
    2805        return INDEX_NOT_FOUND;
    2806    }
    2807
    2808    /**
    2809     * Search a CharSequence to find the first index of any character in the given set of characters.
    2810     *
    2811     * <p>
    2812     * A {@code null} String will return {@code -1}. A {@code null} search string will return {@code -1}.
    2813     * </p>
    2814     *
    2815     * <pre>
    2816     * StringUtils.indexOfAny(null, *)            = -1
    2817     * StringUtils.indexOfAny("", *)              = -1
    2818     * StringUtils.indexOfAny(*, null)            = -1
    2819     * StringUtils.indexOfAny(*, "")              = -1
    2820     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    2821     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    2822     * StringUtils.indexOfAny("aba", "z")         = -1
    2823     * </pre>
    2824     *
    2825     * @param cs          the CharSequence to check, may be null.
    2826     * @param searchChars the chars to search for, may be null.
    2827     * @return the index of any of the chars, -1 if no match or null input.
    2828     * @since 2.0
    2829     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    2830     */
    2831    public static int indexOfAny(final CharSequence cs, final String searchChars) {
    2832        if (isEmpty(cs) || isEmpty(searchChars)) {
    2833            return INDEX_NOT_FOUND;
    2834        }
    2835        return indexOfAny(cs, searchChars.toCharArray());
    2836    }
    2837
    2838    /**
    2839     * Searches a CharSequence to find the first index of any character not in the given set of characters, i.e., find index i of first char in cs such that
    2840     * (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
    2841     *
    2842     * <p>
    2843     * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
    2844     * </p>
    2845     *
    2846     * <pre>
    2847     * StringUtils.indexOfAnyBut(null, *)                              = -1
    2848     * StringUtils.indexOfAnyBut("", *)                                = -1
    2849     * StringUtils.indexOfAnyBut(*, null)                              = -1
    2850     * StringUtils.indexOfAnyBut(*, [])                                = -1
    2851     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
    2852     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
    2853     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
    2854     * </pre>
    2855     *
    2856     * @param cs          the CharSequence to check, may be null.
    2857     * @param searchChars the chars to search for, may be null.
    2858     * @return the index of any of the chars, -1 if no match or null input.
    2859     * @since 2.0
    2860     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
    2861     */
    2862    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    2863        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2864            return INDEX_NOT_FOUND;
    2865        }
    2866        return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
    2867    }
    2868
    2869    /**
    2870     * Search a CharSequence to find the first index of any character not in the given set of characters, i.e., find index i of first char in seq such that
    2871     * (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
    2872     *
    2873     * <p>
    2874     * A {@code null} CharSequence will return {@code -1}. A {@code null} or empty search string will return {@code -1}.
    2875     * </p>
    2876     *
    2877     * <pre>
    2878     * StringUtils.indexOfAnyBut(null, *)            = -1
    2879     * StringUtils.indexOfAnyBut("", *)              = -1
    2880     * StringUtils.indexOfAnyBut(*, null)            = -1
    2881     * StringUtils.indexOfAnyBut(*, "")              = -1
    2882     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    2883     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
    2884     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
    2885     * </pre>
    2886     *
    2887     * @param seq         the CharSequence to check, may be null.
    2888     * @param searchChars the chars to search for, may be null.
    2889     * @return the index of any of the chars, -1 if no match or null input.
    2890     * @since 2.0
    2891     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
    2892     */
    2893    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
    2894        if (isEmpty(seq) || isEmpty(searchChars)) {
    2895            return INDEX_NOT_FOUND;
    2896        }
    2897        final Set<Integer> searchSetCodePoints = searchChars.codePoints()
    2898                .boxed().collect(Collectors.toSet());
    2899        // advance character index from one interpreted codepoint to the next
    2900        for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
    2901            final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
    2902            if (!searchSetCodePoints.contains(curSeqCodePoint)) {
    2903                return curSeqCharIdx;
    2904            }
    2905            curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
    2906        }
    2907        return INDEX_NOT_FOUND;
    2908    }
    2909
    2910    /**
    2911     * Compares all CharSequences in an array and returns the index at which the CharSequences begin to differ.
    2912     *
    2913     * <p>
    2914     * For example, {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}
    2915     * </p>
    2916     *
    2917     * <pre>
    2918     * StringUtils.indexOfDifference(null)                             = -1
    2919     * StringUtils.indexOfDifference(new String[] {})                  = -1
    2920     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
    2921     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
    2922     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
    2923     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
    2924     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    2925     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    2926     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
    2927     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
    2928     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
    2929     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
    2930     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
    2931     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
    2932     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
    2933     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
    2934     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    2935     * </pre>
    2936     *
    2937     * @param css array of CharSequences, entries may be null.
    2938     * @return the index where the strings begin to differ; -1 if they are all equal.
    2939     * @since 2.4
    2940     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    2941     */
    2942    public static int indexOfDifference(final CharSequence... css) {
    2943        if (ArrayUtils.getLength(css) <= 1) {
    2944            return INDEX_NOT_FOUND;
    2945        }
    2946        boolean anyStringNull = false;
    2947        boolean allStringsNull = true;
    2948        final int arrayLen = css.length;
    2949        int shortestStrLen = Integer.MAX_VALUE;
    2950        int longestStrLen = 0;
    2951        // find the min and max string lengths; this avoids checking to make
    2952        // sure we are not exceeding the length of the string each time through
    2953        // the bottom loop.
    2954        for (final CharSequence cs : css) {
    2955            if (cs == null) {
    2956                anyStringNull = true;
    2957                shortestStrLen = 0;
    2958            } else {
    2959                allStringsNull = false;
    2960                shortestStrLen = Math.min(cs.length(), shortestStrLen);
    2961                longestStrLen = Math.max(cs.length(), longestStrLen);
    2962            }
    2963        }
    2964        // handle lists containing all nulls or all empty strings
    2965        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
    2966            return INDEX_NOT_FOUND;
    2967        }
    2968        // handle lists containing some nulls or some empty strings
    2969        if (shortestStrLen == 0) {
    2970            return 0;
    2971        }
    2972        // find the position with the first difference across all strings
    2973        int firstDiff = -1;
    2974        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    2975            final char comparisonChar = css[0].charAt(stringPos);
    2976            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    2977                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    2978                    firstDiff = stringPos;
    2979                    break;
    2980                }
    2981            }
    2982            if (firstDiff != -1) {
    2983                break;
    2984            }
    2985        }
    2986        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    2987            // we compared all of the characters up to the length of the
    2988            // shortest string and didn't find a match, but the string lengths
    2989            // vary, so return the length of the shortest string.
    2990            return shortestStrLen;
    2991        }
    2992        return firstDiff;
    2993    }
    2994
    2995    /**
    2996     * Compares two CharSequences, and returns the index at which the CharSequences begin to differ.
    2997     *
    2998     * <p>
    2999     * For example, {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
    3000     * </p>
    3001     *
    3002     * <pre>
    3003     * StringUtils.indexOfDifference(null, null)       = -1
    3004     * StringUtils.indexOfDifference("", "")           = -1
    3005     * StringUtils.indexOfDifference("", "abc")        = 0
    3006     * StringUtils.indexOfDifference("abc", "")        = 0
    3007     * StringUtils.indexOfDifference("abc", "abc")     = -1
    3008     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
    3009     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    3010     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
    3011     * </pre>
    3012     *
    3013     * @param cs1 the first CharSequence, may be null.
    3014     * @param cs2 the second CharSequence, may be null.
    3015     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal.
    3016     * @since 2.0
    3017     * @since 3.0 Changed signature from indexOfDifference(String, String) to indexOfDifference(CharSequence, CharSequence)
    3018     */
    3019    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
    3020        if (cs1 == cs2) {
    3021            return INDEX_NOT_FOUND;
    3022        }
    3023        if (cs1 == null || cs2 == null) {
    3024            return 0;
    3025        }
    3026        int i;
    3027        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    3028            if (cs1.charAt(i) != cs2.charAt(i)) {
    3029                break;
    3030            }
    3031        }
    3032        if (i < cs2.length() || i < cs1.length()) {
    3033            return i;
    3034        }
    3035        return INDEX_NOT_FOUND;
    3036    }
    3037
    3038    /**
    3039     * Case in-sensitive find of the first index within a CharSequence.
    3040     *
    3041     * <p>
    3042     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
    3043     * start position greater than the string length only matches an empty search CharSequence.
    3044     * </p>
    3045     *
    3046     * <pre>
    3047     * StringUtils.indexOfIgnoreCase(null, *)          = -1
    3048     * StringUtils.indexOfIgnoreCase(*, null)          = -1
    3049     * StringUtils.indexOfIgnoreCase("", "")           = 0
    3050     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
    3051     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    3052     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    3053     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    3054     * </pre>
    3055     *
    3056     * @param str       the CharSequence to check, may be null.
    3057     * @param searchStr the CharSequence to find, may be null.
    3058     * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
    3059     * @since 2.5
    3060     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
    3061     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}
    3062     */
    3063    @Deprecated
    3064    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    3065        return Strings.CI.indexOf(str, searchStr);
    3066    }
    3067
    3068    /**
    3069     * Case in-sensitive find of the first index within a CharSequence from the specified position.
    3070     *
    3071     * <p>
    3072     * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
    3073     * start position greater than the string length only matches an empty search CharSequence.
    3074     * </p>
    3075     *
    3076     * <pre>
    3077     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    3078     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    3079     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    3080     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    3081     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    3082     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    3083     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    3084     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    3085     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    3086     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    3087     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
    3088     * </pre>
    3089     *
    3090     * @param str       the CharSequence to check, may be null.
    3091     * @param searchStr the CharSequence to find, may be null.
    3092     * @param startPos  the start position, negative treated as zero.
    3093     * @return the first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
    3094     * @since 2.5
    3095     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
    3096     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}
    3097     */
    3098    @Deprecated
    3099    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
    3100        return Strings.CI.indexOf(str, searchStr, startPos);
    3101    }
    3102
    3103    /**
    3104     * Tests if all of the CharSequences are empty (""), null or whitespace only.
    3105     *
    3106     * <p>
    3107     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3108     * </p>
    3109     *
    3110     * <pre>
    3111     * StringUtils.isAllBlank(null)             = true
    3112     * StringUtils.isAllBlank(null, "foo")      = false
    3113     * StringUtils.isAllBlank(null, null)       = true
    3114     * StringUtils.isAllBlank("", "bar")        = false
    3115     * StringUtils.isAllBlank("bob", "")        = false
    3116     * StringUtils.isAllBlank("  bob  ", null)  = false
    3117     * StringUtils.isAllBlank(" ", "bar")       = false
    3118     * StringUtils.isAllBlank("foo", "bar")     = false
    3119     * StringUtils.isAllBlank(new String[] {})  = true
    3120     * </pre>
    3121     *
    3122     * @param css the CharSequences to check, may be null or empty.
    3123     * @return {@code true} if all of the CharSequences are empty or null or whitespace only.
    3124     * @since 3.6
    3125     */
    3126    public static boolean isAllBlank(final CharSequence... css) {
    3127        if (ArrayUtils.isEmpty(css)) {
    3128            return true;
    3129        }
    3130        for (final CharSequence cs : css) {
    3131            if (isNotBlank(cs)) {
    3132               return false;
    3133            }
    3134        }
    3135        return true;
    3136    }
    3137
    3138    /**
    3139     * Tests if all of the CharSequences are empty ("") or null.
    3140     *
    3141     * <pre>
    3142     * StringUtils.isAllEmpty(null)             = true
    3143     * StringUtils.isAllEmpty(null, "")         = true
    3144     * StringUtils.isAllEmpty(new String[] {})  = true
    3145     * StringUtils.isAllEmpty(null, "foo")      = false
    3146     * StringUtils.isAllEmpty("", "bar")        = false
    3147     * StringUtils.isAllEmpty("bob", "")        = false
    3148     * StringUtils.isAllEmpty("  bob  ", null)  = false
    3149     * StringUtils.isAllEmpty(" ", "bar")       = false
    3150     * StringUtils.isAllEmpty("foo", "bar")     = false
    3151     * </pre>
    3152     *
    3153     * @param css the CharSequences to check, may be null or empty.
    3154     * @return {@code true} if all of the CharSequences are empty or null.
    3155     * @since 3.6
    3156     */
    3157    public static boolean isAllEmpty(final CharSequence... css) {
    3158        if (ArrayUtils.isEmpty(css)) {
    3159            return true;
    3160        }
    3161        for (final CharSequence cs : css) {
    3162            if (isNotEmpty(cs)) {
    3163                return false;
    3164            }
    3165        }
    3166        return true;
    3167    }
    3168
    3169    /**
    3170     * Tests if the CharSequence contains only lowercase characters.
    3171     *
    3172     * <p>
    3173     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
    3174     * </p>
    3175     *
    3176     * <pre>
    3177     * StringUtils.isAllLowerCase(null)   = false
    3178     * StringUtils.isAllLowerCase("")     = false
    3179     * StringUtils.isAllLowerCase("  ")   = false
    3180     * StringUtils.isAllLowerCase("abc")  = true
    3181     * StringUtils.isAllLowerCase("abC")  = false
    3182     * StringUtils.isAllLowerCase("ab c") = false
    3183     * StringUtils.isAllLowerCase("ab1c") = false
    3184     * StringUtils.isAllLowerCase("ab/c") = false
    3185     * </pre>
    3186     *
    3187     * @param cs the CharSequence to check, may be null.
    3188     * @return {@code true} if only contains lowercase characters, and is non-null.
    3189     * @since 2.5
    3190     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    3191     */
    3192    public static boolean isAllLowerCase(final CharSequence cs) {
    3193        if (isEmpty(cs)) {
    3194            return false;
    3195        }
    3196        final int sz = cs.length();
    3197        for (int i = 0; i < sz; i++) {
    3198            if (!Character.isLowerCase(cs.charAt(i))) {
    3199                return false;
    3200            }
    3201        }
    3202        return true;
    3203    }
    3204
    3205    /**
    3206     * Tests if the CharSequence contains only uppercase characters.
    3207     *
    3208     * <p>{@code null} will return {@code false}.
    3209     * An empty String (length()=0) will return {@code false}.</p>
    3210     *
    3211     * <pre>
    3212     * StringUtils.isAllUpperCase(null)   = false
    3213     * StringUtils.isAllUpperCase("")     = false
    3214     * StringUtils.isAllUpperCase("  ")   = false
    3215     * StringUtils.isAllUpperCase("ABC")  = true
    3216     * StringUtils.isAllUpperCase("aBC")  = false
    3217     * StringUtils.isAllUpperCase("A C")  = false
    3218     * StringUtils.isAllUpperCase("A1C")  = false
    3219     * StringUtils.isAllUpperCase("A/C")  = false
    3220     * </pre>
    3221     *
    3222     * @param cs the CharSequence to check, may be null.
    3223     * @return {@code true} if only contains uppercase characters, and is non-null.
    3224     * @since 2.5
    3225     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    3226     */
    3227    public static boolean isAllUpperCase(final CharSequence cs) {
    3228        if (isEmpty(cs)) {
    3229            return false;
    3230        }
    3231        final int sz = cs.length();
    3232        for (int i = 0; i < sz; i++) {
    3233            if (!Character.isUpperCase(cs.charAt(i))) {
    3234                return false;
    3235            }
    3236        }
    3237        return true;
    3238    }
    3239
    3240    /**
    3241     * Tests if the CharSequence contains only Unicode letters.
    3242     *
    3243     * <p>
    3244     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
    3245     * </p>
    3246     *
    3247     * <pre>
    3248     * StringUtils.isAlpha(null)   = false
    3249     * StringUtils.isAlpha("")     = false
    3250     * StringUtils.isAlpha("  ")   = false
    3251     * StringUtils.isAlpha("abc")  = true
    3252     * StringUtils.isAlpha("ab2c") = false
    3253     * StringUtils.isAlpha("ab-c") = false
    3254     * </pre>
    3255     *
    3256     * @param cs the CharSequence to check, may be null.
    3257     * @return {@code true} if only contains letters, and is non-null.
    3258     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    3259     * @since 3.0 Changed "" to return false and not true
    3260     */
    3261    public static boolean isAlpha(final CharSequence cs) {
    3262        if (isEmpty(cs)) {
    3263            return false;
    3264        }
    3265        final int sz = cs.length();
    3266        for (int i = 0; i < sz; i++) {
    3267            if (!Character.isLetter(cs.charAt(i))) {
    3268                return false;
    3269            }
    3270        }
    3271        return true;
    3272    }
    3273
    3274    /**
    3275     * Tests if the CharSequence contains only Unicode letters or digits.
    3276     *
    3277     * <p>
    3278     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
    3279     * </p>
    3280     *
    3281     * <pre>
    3282     * StringUtils.isAlphanumeric(null)   = false
    3283     * StringUtils.isAlphanumeric("")     = false
    3284     * StringUtils.isAlphanumeric("  ")   = false
    3285     * StringUtils.isAlphanumeric("abc")  = true
    3286     * StringUtils.isAlphanumeric("ab c") = false
    3287     * StringUtils.isAlphanumeric("ab2c") = true
    3288     * StringUtils.isAlphanumeric("ab-c") = false
    3289     * </pre>
    3290     *
    3291     * @param cs the CharSequence to check, may be null.
    3292     * @return {@code true} if only contains letters or digits, and is non-null.
    3293     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    3294     * @since 3.0 Changed "" to return false and not true
    3295     */
    3296    public static boolean isAlphanumeric(final CharSequence cs) {
    3297        if (isEmpty(cs)) {
    3298            return false;
    3299        }
    3300        final int sz = cs.length();
    3301        for (int i = 0; i < sz; i++) {
    3302            if (!Character.isLetterOrDigit(cs.charAt(i))) {
    3303                return false;
    3304            }
    3305        }
    3306        return true;
    3307    }
    3308
    3309    /**
    3310     * Tests if the CharSequence contains only Unicode letters, digits or space ({@code ' '}).
    3311     *
    3312     * <p>
    3313     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
    3314     * </p>
    3315     *
    3316     * <pre>
    3317     * StringUtils.isAlphanumericSpace(null)   = false
    3318     * StringUtils.isAlphanumericSpace("")     = true
    3319     * StringUtils.isAlphanumericSpace("  ")   = true
    3320     * StringUtils.isAlphanumericSpace("abc")  = true
    3321     * StringUtils.isAlphanumericSpace("ab c") = true
    3322     * StringUtils.isAlphanumericSpace("ab2c") = true
    3323     * StringUtils.isAlphanumericSpace("ab-c") = false
    3324     * </pre>
    3325     *
    3326     * @param cs the CharSequence to check, may be null.
    3327     * @return {@code true} if only contains letters, digits or space, and is non-null.
    3328     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    3329     */
    3330    public static boolean isAlphanumericSpace(final CharSequence cs) {
    3331        if (cs == null) {
    3332            return false;
    3333        }
    3334        final int sz = cs.length();
    3335        for (int i = 0; i < sz; i++) {
    3336            final char nowChar = cs.charAt(i);
    3337            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar)) {
    3338                return false;
    3339            }
    3340        }
    3341        return true;
    3342    }
    3343
    3344    /**
    3345     * Tests if the CharSequence contains only Unicode letters and space (' ').
    3346     *
    3347     * <p>
    3348     * {@code null} will return {@code false} An empty CharSequence (length()=0) will return {@code true}.
    3349     * </p>
    3350     *
    3351     * <pre>
    3352     * StringUtils.isAlphaSpace(null)   = false
    3353     * StringUtils.isAlphaSpace("")     = true
    3354     * StringUtils.isAlphaSpace("  ")   = true
    3355     * StringUtils.isAlphaSpace("abc")  = true
    3356     * StringUtils.isAlphaSpace("ab c") = true
    3357     * StringUtils.isAlphaSpace("ab2c") = false
    3358     * StringUtils.isAlphaSpace("ab-c") = false
    3359     * </pre>
    3360     *
    3361     * @param cs the CharSequence to check, may be null.
    3362     * @return {@code true} if only contains letters and space, and is non-null.
    3363     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    3364     */
    3365    public static boolean isAlphaSpace(final CharSequence cs) {
    3366        if (cs == null) {
    3367            return false;
    3368        }
    3369        final int sz = cs.length();
    3370        for (int i = 0; i < sz; i++) {
    3371            final char nowChar = cs.charAt(i);
    3372            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
    3373                return false;
    3374            }
    3375        }
    3376        return true;
    3377    }
    3378
    3379    /**
    3380     * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
    3381     *
    3382     * <p>
    3383     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3384     * </p>
    3385     *
    3386     * <pre>
    3387     * StringUtils.isAnyBlank((String) null)    = true
    3388     * StringUtils.isAnyBlank((String[]) null)  = false
    3389     * StringUtils.isAnyBlank(null, "foo")      = true
    3390     * StringUtils.isAnyBlank(null, null)       = true
    3391     * StringUtils.isAnyBlank("", "bar")        = true
    3392     * StringUtils.isAnyBlank("bob", "")        = true
    3393     * StringUtils.isAnyBlank("  bob  ", null)  = true
    3394     * StringUtils.isAnyBlank(" ", "bar")       = true
    3395     * StringUtils.isAnyBlank(new String[] {})  = false
    3396     * StringUtils.isAnyBlank(new String[]{""}) = true
    3397     * StringUtils.isAnyBlank("foo", "bar")     = false
    3398     * </pre>
    3399     *
    3400     * @param css the CharSequences to check, may be null or empty.
    3401     * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
    3402     * @see #isBlank(CharSequence)
    3403     * @since 3.2
    3404     */
    3405    public static boolean isAnyBlank(final CharSequence... css) {
    3406        if (ArrayUtils.isEmpty(css)) {
    3407            return false;
    3408        }
    3409        for (final CharSequence cs : css) {
    3410            if (isBlank(cs)) {
    3411                return true;
    3412            }
    3413        }
    3414        return false;
    3415    }
    3416
    3417    /**
    3418     * Tests if any of the CharSequences are empty ("") or null.
    3419     *
    3420     * <pre>
    3421     * StringUtils.isAnyEmpty((String) null)    = true
    3422     * StringUtils.isAnyEmpty((String[]) null)  = false
    3423     * StringUtils.isAnyEmpty(null, "foo")      = true
    3424     * StringUtils.isAnyEmpty("", "bar")        = true
    3425     * StringUtils.isAnyEmpty("bob", "")        = true
    3426     * StringUtils.isAnyEmpty("  bob  ", null)  = true
    3427     * StringUtils.isAnyEmpty(" ", "bar")       = false
    3428     * StringUtils.isAnyEmpty("foo", "bar")     = false
    3429     * StringUtils.isAnyEmpty(new String[]{})   = false
    3430     * StringUtils.isAnyEmpty(new String[]{""}) = true
    3431     * </pre>
    3432     *
    3433     * @param css  the CharSequences to check, may be null or empty.
    3434     * @return {@code true} if any of the CharSequences are empty or null.
    3435     * @since 3.2
    3436     */
    3437    public static boolean isAnyEmpty(final CharSequence... css) {
    3438        if (ArrayUtils.isEmpty(css)) {
    3439            return false;
    3440        }
    3441        for (final CharSequence cs : css) {
    3442            if (isEmpty(cs)) {
    3443                return true;
    3444            }
    3445        }
    3446        return false;
    3447    }
    3448
    3449    /**
    3450     * Tests if the CharSequence contains only ASCII printable characters.
    3451     *
    3452     * <p>
    3453     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
    3454     * </p>
    3455     *
    3456     * <pre>
    3457     * StringUtils.isAsciiPrintable(null)     = false
    3458     * StringUtils.isAsciiPrintable("")       = true
    3459     * StringUtils.isAsciiPrintable(" ")      = true
    3460     * StringUtils.isAsciiPrintable("Ceki")   = true
    3461     * StringUtils.isAsciiPrintable("ab2c")   = true
    3462     * StringUtils.isAsciiPrintable("!ab-c~") = true
    3463     * StringUtils.isAsciiPrintable("\u0020") = true
    3464     * StringUtils.isAsciiPrintable("\u0021") = true
    3465     * StringUtils.isAsciiPrintable("\u007e") = true
    3466     * StringUtils.isAsciiPrintable("\u007f") = false
    3467     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    3468     * </pre>
    3469     *
    3470     * @param cs the CharSequence to check, may be null.
    3471     * @return {@code true} if every character is in the range 32 through 126.
    3472     * @since 2.1
    3473     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    3474     */
    3475    public static boolean isAsciiPrintable(final CharSequence cs) {
    3476        if (cs == null) {
    3477            return false;
    3478        }
    3479        final int sz = cs.length();
    3480        for (int i = 0; i < sz; i++) {
    3481            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
    3482                return false;
    3483            }
    3484        }
    3485        return true;
    3486    }
    3487
    3488    /**
    3489     * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
    3490     *
    3491     * <pre>
    3492     * StringUtils.isBlank(null)      = true
    3493     * StringUtils.isBlank("")        = true
    3494     * StringUtils.isBlank(" ")       = true
    3495     * StringUtils.isBlank("bob")     = false
    3496     * StringUtils.isBlank("  bob  ") = false
    3497     * </pre>
    3498     *
    3499     * @param cs the CharSequence to check, may be null.
    3500     * @return {@code true} if the CharSequence is null, empty or whitespace only.
    3501     * @since 2.0
    3502     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    3503     */
    3504    public static boolean isBlank(final CharSequence cs) {
    3505        final int strLen = length(cs);
    3506        if (strLen == 0) {
    3507            return true;
    3508        }
    3509        for (int i = 0; i < strLen; i++) {
    3510            if (!Character.isWhitespace(cs.charAt(i))) {
    3511                return false;
    3512            }
    3513        }
    3514        return true;
    3515    }
    3516
    3517    /**
    3518     * Tests if a CharSequence is empty ("") or null.
    3519     *
    3520     * <pre>
    3521     * StringUtils.isEmpty(null)      = true
    3522     * StringUtils.isEmpty("")        = true
    3523     * StringUtils.isEmpty(" ")       = false
    3524     * StringUtils.isEmpty("bob")     = false
    3525     * StringUtils.isEmpty("  bob  ") = false
    3526     * </pre>
    3527     *
    3528     * <p>
    3529     * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is available in isBlank().
    3530     * </p>
    3531     *
    3532     * @param cs the CharSequence to check, may be null.
    3533     * @return {@code true} if the CharSequence is empty or null.
    3534     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    3535     */
    3536    public static boolean isEmpty(final CharSequence cs) {
    3537        return cs == null || cs.length() == 0;
    3538    }
    3539
    3540    /**
    3541     * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
    3542     *
    3543     * <p>
    3544     * {@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return {@code false}.
    3545     * </p>
    3546     *
    3547     * <pre>
    3548     * StringUtils.isMixedCase(null)    = false
    3549     * StringUtils.isMixedCase("")      = false
    3550     * StringUtils.isMixedCase(" ")     = false
    3551     * StringUtils.isMixedCase("ABC")   = false
    3552     * StringUtils.isMixedCase("abc")   = false
    3553     * StringUtils.isMixedCase("aBc")   = true
    3554     * StringUtils.isMixedCase("A c")   = true
    3555     * StringUtils.isMixedCase("A1c")   = true
    3556     * StringUtils.isMixedCase("a/C")   = true
    3557     * StringUtils.isMixedCase("aC\t")  = true
    3558     * </pre>
    3559     *
    3560     * @param cs the CharSequence to check, may be null.
    3561     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters.
    3562     * @since 3.5
    3563     */
    3564    public static boolean isMixedCase(final CharSequence cs) {
    3565        if (isEmpty(cs) || cs.length() == 1) {
    3566            return false;
    3567        }
    3568        boolean containsUppercase = false;
    3569        boolean containsLowercase = false;
    3570        final int sz = cs.length();
    3571        for (int i = 0; i < sz; i++) {
    3572            final char nowChar = cs.charAt(i);
    3573            if (Character.isUpperCase(nowChar)) {
    3574                containsUppercase = true;
    3575            } else if (Character.isLowerCase(nowChar)) {
    3576                containsLowercase = true;
    3577            }
    3578            if (containsUppercase && containsLowercase) {
    3579                return true;
    3580            }
    3581        }
    3582        return false;
    3583    }
    3584
    3585    /**
    3586     * Tests if none of the CharSequences are empty (""), null or whitespace only.
    3587     *
    3588     * <p>
    3589     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3590     * </p>
    3591     *
    3592     * <pre>
    3593     * StringUtils.isNoneBlank((String) null)    = false
    3594     * StringUtils.isNoneBlank((String[]) null)  = true
    3595     * StringUtils.isNoneBlank(null, "foo")      = false
    3596     * StringUtils.isNoneBlank(null, null)       = false
    3597     * StringUtils.isNoneBlank("", "bar")        = false
    3598     * StringUtils.isNoneBlank("bob", "")        = false
    3599     * StringUtils.isNoneBlank("  bob  ", null)  = false
    3600     * StringUtils.isNoneBlank(" ", "bar")       = false
    3601     * StringUtils.isNoneBlank(new String[] {})  = true
    3602     * StringUtils.isNoneBlank(new String[]{""}) = false
    3603     * StringUtils.isNoneBlank("foo", "bar")     = true
    3604     * </pre>
    3605     *
    3606     * @param css the CharSequences to check, may be null or empty.
    3607     * @return {@code true} if none of the CharSequences are empty or null or whitespace only.
    3608     * @since 3.2
    3609     */
    3610    public static boolean isNoneBlank(final CharSequence... css) {
    3611      return !isAnyBlank(css);
    3612    }
    3613
    3614    /**
    3615     * Tests if none of the CharSequences are empty ("") or null.
    3616     *
    3617     * <pre>
    3618     * StringUtils.isNoneEmpty((String) null)    = false
    3619     * StringUtils.isNoneEmpty((String[]) null)  = true
    3620     * StringUtils.isNoneEmpty(null, "foo")      = false
    3621     * StringUtils.isNoneEmpty("", "bar")        = false
    3622     * StringUtils.isNoneEmpty("bob", "")        = false
    3623     * StringUtils.isNoneEmpty("  bob  ", null)  = false
    3624     * StringUtils.isNoneEmpty(new String[] {})  = true
    3625     * StringUtils.isNoneEmpty(new String[]{""}) = false
    3626     * StringUtils.isNoneEmpty(" ", "bar")       = true
    3627     * StringUtils.isNoneEmpty("foo", "bar")     = true
    3628     * </pre>
    3629     *
    3630     * @param css  the CharSequences to check, may be null or empty.
    3631     * @return {@code true} if none of the CharSequences are empty or null.
    3632     * @since 3.2
    3633     */
    3634    public static boolean isNoneEmpty(final CharSequence... css) {
    3635      return !isAnyEmpty(css);
    3636    }
    3637
    3638    /**
    3639     * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
    3640     *
    3641     * <p>
    3642     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3643     * </p>
    3644     *
    3645     * <pre>
    3646     * StringUtils.isNotBlank(null)      = false
    3647     * StringUtils.isNotBlank("")        = false
    3648     * StringUtils.isNotBlank(" ")       = false
    3649     * StringUtils.isNotBlank("bob")     = true
    3650     * StringUtils.isNotBlank("  bob  ") = true
    3651     * </pre>
    3652     *
    3653     * @param cs the CharSequence to check, may be null.
    3654     * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
    3655     * @see #isBlank(CharSequence)
    3656     * @since 2.0
    3657     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    3658     */
    3659    public static boolean isNotBlank(final CharSequence cs) {
    3660        return !isBlank(cs);
    3661    }
    3662
    3663    /**
    3664     * Tests if a CharSequence is not empty ("") and not null.
    3665     *
    3666     * <pre>
    3667     * StringUtils.isNotEmpty(null)      = false
    3668     * StringUtils.isNotEmpty("")        = false
    3669     * StringUtils.isNotEmpty(" ")       = true
    3670     * StringUtils.isNotEmpty("bob")     = true
    3671     * StringUtils.isNotEmpty("  bob  ") = true
    3672     * </pre>
    3673     *
    3674     * @param cs  the CharSequence to check, may be null.
    3675     * @return {@code true} if the CharSequence is not empty and not null.
    3676     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    3677     */
    3678    public static boolean isNotEmpty(final CharSequence cs) {
    3679        return !isEmpty(cs);
    3680    }
    3681
    3682    /**
    3683     * Tests if the CharSequence contains only Unicode digits. A decimal point is not a Unicode digit and returns false.
    3684     *
    3685     * <p>
    3686     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
    3687     * </p>
    3688     *
    3689     * <p>
    3690     * 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
    3691     * NumberFormatException when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range for int or long respectively.
    3692     * </p>
    3693     *
    3694     * <pre>
    3695     * StringUtils.isNumeric(null)   = false
    3696     * StringUtils.isNumeric("")     = false
    3697     * StringUtils.isNumeric("  ")   = false
    3698     * StringUtils.isNumeric("123")  = true
    3699     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    3700     * StringUtils.isNumeric("12 3") = false
    3701     * StringUtils.isNumeric("ab2c") = false
    3702     * StringUtils.isNumeric("12-3") = false
    3703     * StringUtils.isNumeric("12.3") = false
    3704     * StringUtils.isNumeric("-123") = false
    3705     * StringUtils.isNumeric("+123") = false
    3706     * </pre>
    3707     *
    3708     * @param cs the CharSequence to check, may be null.
    3709     * @return {@code true} if only contains digits, and is non-null.
    3710     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    3711     * @since 3.0 Changed "" to return false and not true
    3712     */
    3713    public static boolean isNumeric(final CharSequence cs) {
    3714        if (isEmpty(cs)) {
    3715            return false;
    3716        }
    3717        final int sz = cs.length();
    3718        for (int i = 0; i < sz; i++) {
    3719            if (!Character.isDigit(cs.charAt(i))) {
    3720                return false;
    3721            }
    3722        }
    3723        return true;
    3724    }
    3725
    3726    /**
    3727     * Tests if the CharSequence contains only Unicode digits or space ({@code ' '}). A decimal point is not a Unicode digit and returns false.
    3728     *
    3729     * <p>
    3730     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
    3731     * </p>
    3732     *
    3733     * <pre>
    3734     * StringUtils.isNumericSpace(null)   = false
    3735     * StringUtils.isNumericSpace("")     = true
    3736     * StringUtils.isNumericSpace("  ")   = true
    3737     * StringUtils.isNumericSpace("123")  = true
    3738     * StringUtils.isNumericSpace("12 3") = true
    3739     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
    3740     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
    3741     * StringUtils.isNumericSpace("ab2c") = false
    3742     * StringUtils.isNumericSpace("12-3") = false
    3743     * StringUtils.isNumericSpace("12.3") = false
    3744     * </pre>
    3745     *
    3746     * @param cs the CharSequence to check, may be null.
    3747     * @return {@code true} if only contains digits or space, and is non-null.
    3748     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    3749     */
    3750    public static boolean isNumericSpace(final CharSequence cs) {
    3751        if (cs == null) {
    3752            return false;
    3753        }
    3754        final int sz = cs.length();
    3755        for (int i = 0; i < sz; i++) {
    3756            final char nowChar = cs.charAt(i);
    3757            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
    3758                return false;
    3759            }
    3760        }
    3761        return true;
    3762    }
    3763
    3764    /**
    3765     * Tests if the CharSequence contains only whitespace.
    3766     *
    3767     * <p>
    3768     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3769     * </p>
    3770     *
    3771     * <p>
    3772     * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
    3773     * </p>
    3774     *
    3775     * <pre>
    3776     * StringUtils.isWhitespace(null)   = false
    3777     * StringUtils.isWhitespace("")     = true
    3778     * StringUtils.isWhitespace("  ")   = true
    3779     * StringUtils.isWhitespace("abc")  = false
    3780     * StringUtils.isWhitespace("ab2c") = false
    3781     * StringUtils.isWhitespace("ab-c") = false
    3782     * </pre>
    3783     *
    3784     * @param cs the CharSequence to check, may be null.
    3785     * @return {@code true} if only contains whitespace, and is non-null.
    3786     * @since 2.0
    3787     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    3788     */
    3789    public static boolean isWhitespace(final CharSequence cs) {
    3790        if (cs == null) {
    3791            return false;
    3792        }
    3793        final int sz = cs.length();
    3794        for (int i = 0; i < sz; i++) {
    3795            if (!Character.isWhitespace(cs.charAt(i))) {
    3796                return false;
    3797            }
    3798        }
    3799        return true;
    3800    }
    3801
    3802    /**
    3803     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3804     *
    3805     * <p>
    3806     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
    3807     * </p>
    3808     *
    3809     * <pre>
    3810     * StringUtils.join(null, *)             = null
    3811     * StringUtils.join([], *)               = ""
    3812     * StringUtils.join([null], *)           = ""
    3813     * StringUtils.join([false, false], ';') = "false;false"
    3814     * </pre>
    3815     *
    3816     * @param array     the array of values to join together, may be null.
    3817     * @param delimiter the separator character to use.
    3818     * @return the joined String, {@code null} if null array input.
    3819     * @since 3.12.0
    3820     */
    3821    public static String join(final boolean[] array, final char delimiter) {
    3822        if (array == null) {
    3823            return null;
    3824        }
    3825        return join(array, delimiter, 0, array.length);
    3826    }
    3827
    3828    /**
    3829     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3830     *
    3831     * <p>
    3832     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3833     * by empty strings.
    3834     * </p>
    3835     *
    3836     * <pre>
    3837     * StringUtils.join(null, *)                  = null
    3838     * StringUtils.join([], *)                    = ""
    3839     * StringUtils.join([null], *)                = ""
    3840     * StringUtils.join([true, false, true], ';') = "true;false;true"
    3841     * </pre>
    3842     *
    3843     * @param array
    3844     *            the array of values to join together, may be null.
    3845     * @param delimiter
    3846     *            the separator character to use.
    3847     * @param startIndex
    3848     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3849     *            array.
    3850     * @param endIndex
    3851     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3852     *            the array.
    3853     * @return the joined String, {@code null} if null array input.
    3854     * @since 3.12.0
    3855     */
    3856    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
    3857        if (array == null) {
    3858            return null;
    3859        }
    3860        if (endIndex - startIndex <= 0) {
    3861            return EMPTY;
    3862        }
    3863        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
    3864        for (int i = startIndex; i < endIndex; i++) {
    3865            stringBuilder
    3866                    .append(array[i])
    3867                    .append(delimiter);
    3868        }
    3869        return stringBuilder.substring(0, stringBuilder.length() - 1);
    3870    }
    3871
    3872    /**
    3873     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3874     *
    3875     * <p>
    3876     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3877     * by empty strings.
    3878     * </p>
    3879     *
    3880     * <pre>
    3881     * StringUtils.join(null, *)         = null
    3882     * StringUtils.join([], *)           = ""
    3883     * StringUtils.join([null], *)       = ""
    3884     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3885     * StringUtils.join([1, 2, 3], null) = "123"
    3886     * </pre>
    3887     *
    3888     * @param array
    3889     *            the array of values to join together, may be null.
    3890     * @param delimiter
    3891     *            the separator character to use.
    3892     * @return the joined String, {@code null} if null array input.
    3893     * @since 3.2
    3894     */
    3895    public static String join(final byte[] array, final char delimiter) {
    3896        if (array == null) {
    3897            return null;
    3898        }
    3899        return join(array, delimiter, 0, array.length);
    3900    }
    3901
    3902    /**
    3903     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3904     *
    3905     * <p>
    3906     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3907     * by empty strings.
    3908     * </p>
    3909     *
    3910     * <pre>
    3911     * StringUtils.join(null, *)         = null
    3912     * StringUtils.join([], *)           = ""
    3913     * StringUtils.join([null], *)       = ""
    3914     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3915     * StringUtils.join([1, 2, 3], null) = "123"
    3916     * </pre>
    3917     *
    3918     * @param array
    3919     *            the array of values to join together, may be null.
    3920     * @param delimiter
    3921     *            the separator character to use.
    3922     * @param startIndex
    3923     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3924     *            array.
    3925     * @param endIndex
    3926     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3927     *            the array.
    3928     * @return the joined String, {@code null} if null array input.
    3929     * @since 3.2
    3930     */
    3931    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
    3932        if (array == null) {
    3933            return null;
    3934        }
    3935        if (endIndex - startIndex <= 0) {
    3936            return EMPTY;
    3937        }
    3938        final StringBuilder stringBuilder = new StringBuilder();
    3939        for (int i = startIndex; i < endIndex; i++) {
    3940            stringBuilder
    3941                    .append(array[i])
    3942                    .append(delimiter);
    3943        }
    3944        return stringBuilder.substring(0, stringBuilder.length() - 1);
    3945    }
    3946
    3947    /**
    3948     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3949     *
    3950     * <p>
    3951     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3952     * by empty strings.
    3953     * </p>
    3954     *
    3955     * <pre>
    3956     * StringUtils.join(null, *)         = null
    3957     * StringUtils.join([], *)           = ""
    3958     * StringUtils.join([null], *)       = ""
    3959     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3960     * StringUtils.join([1, 2, 3], null) = "123"
    3961     * </pre>
    3962     *
    3963     * @param array
    3964     *            the array of values to join together, may be null.
    3965     * @param delimiter
    3966     *            the separator character to use.
    3967     * @return the joined String, {@code null} if null array input.
    3968     * @since 3.2
    3969     */
    3970    public static String join(final char[] array, final char delimiter) {
    3971        if (array == null) {
    3972            return null;
    3973        }
    3974        return join(array, delimiter, 0, array.length);
    3975    }
    3976
    3977    /**
    3978     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3979     *
    3980     * <p>
    3981     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3982     * by empty strings.
    3983     * </p>
    3984     *
    3985     * <pre>
    3986     * StringUtils.join(null, *)         = null
    3987     * StringUtils.join([], *)           = ""
    3988     * StringUtils.join([null], *)       = ""
    3989     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3990     * StringUtils.join([1, 2, 3], null) = "123"
    3991     * </pre>
    3992     *
    3993     * @param array
    3994     *            the array of values to join together, may be null.
    3995     * @param delimiter
    3996     *            the separator character to use.
    3997     * @param startIndex
    3998     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3999     *            array.
    4000     * @param endIndex
    4001     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4002     *            the array.
    4003     * @return the joined String, {@code null} if null array input.
    4004     * @since 3.2
    4005     */
    4006    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
    4007        if (array == null) {
    4008            return null;
    4009        }
    4010        if (endIndex - startIndex <= 0) {
    4011            return EMPTY;
    4012        }
    4013        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
    4014        for (int i = startIndex; i < endIndex; i++) {
    4015            stringBuilder
    4016                    .append(array[i])
    4017                    .append(delimiter);
    4018        }
    4019        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4020    }
    4021
    4022    /**
    4023     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4024     *
    4025     * <p>
    4026     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4027     * by empty strings.
    4028     * </p>
    4029     *
    4030     * <pre>
    4031     * StringUtils.join(null, *)          = null
    4032     * StringUtils.join([], *)            = ""
    4033     * StringUtils.join([null], *)        = ""
    4034     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4035     * StringUtils.join([1, 2, 3], null)  = "123"
    4036     * </pre>
    4037     *
    4038     * @param array
    4039     *            the array of values to join together, may be null.
    4040     * @param delimiter
    4041     *            the separator character to use.
    4042     * @return the joined String, {@code null} if null array input.
    4043     * @since 3.2
    4044     */
    4045    public static String join(final double[] array, final char delimiter) {
    4046        if (array == null) {
    4047            return null;
    4048        }
    4049        return join(array, delimiter, 0, array.length);
    4050    }
    4051
    4052    /**
    4053     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4054     *
    4055     * <p>
    4056     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4057     * by empty strings.
    4058     * </p>
    4059     *
    4060     * <pre>
    4061     * StringUtils.join(null, *)          = null
    4062     * StringUtils.join([], *)            = ""
    4063     * StringUtils.join([null], *)        = ""
    4064     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4065     * StringUtils.join([1, 2, 3], null)  = "123"
    4066     * </pre>
    4067     *
    4068     * @param array
    4069     *            the array of values to join together, may be null.
    4070     * @param delimiter
    4071     *            the separator character to use.
    4072     * @param startIndex
    4073     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4074     *            array.
    4075     * @param endIndex
    4076     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4077     *            the array.
    4078     * @return the joined String, {@code null} if null array input.
    4079     * @since 3.2
    4080     */
    4081    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
    4082        if (array == null) {
    4083            return null;
    4084        }
    4085        if (endIndex - startIndex <= 0) {
    4086            return EMPTY;
    4087        }
    4088        final StringBuilder stringBuilder = new StringBuilder();
    4089        for (int i = startIndex; i < endIndex; i++) {
    4090            stringBuilder
    4091                    .append(array[i])
    4092                    .append(delimiter);
    4093        }
    4094        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4095    }
    4096
    4097    /**
    4098     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4099     *
    4100     * <p>
    4101     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4102     * by empty strings.
    4103     * </p>
    4104     *
    4105     * <pre>
    4106     * StringUtils.join(null, *)          = null
    4107     * StringUtils.join([], *)            = ""
    4108     * StringUtils.join([null], *)        = ""
    4109     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4110     * StringUtils.join([1, 2, 3], null)  = "123"
    4111     * </pre>
    4112     *
    4113     * @param array
    4114     *            the array of values to join together, may be null.
    4115     * @param delimiter
    4116     *            the separator character to use.
    4117     * @return the joined String, {@code null} if null array input
    4118     * @since 3.2
    4119     */
    4120    public static String join(final float[] array, final char delimiter) {
    4121        if (array == null) {
    4122            return null;
    4123        }
    4124        return join(array, delimiter, 0, array.length);
    4125    }
    4126
    4127    /**
    4128     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4129     *
    4130     * <p>
    4131     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4132     * by empty strings.
    4133     * </p>
    4134     *
    4135     * <pre>
    4136     * StringUtils.join(null, *)          = null
    4137     * StringUtils.join([], *)            = ""
    4138     * StringUtils.join([null], *)        = ""
    4139     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4140     * StringUtils.join([1, 2, 3], null)  = "123"
    4141     * </pre>
    4142     *
    4143     * @param array
    4144     *            the array of values to join together, may be null.
    4145     * @param delimiter
    4146     *            the separator character to use.
    4147     * @param startIndex
    4148     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4149     *            array.
    4150     * @param endIndex
    4151     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4152     *            the array.
    4153     * @return the joined String, {@code null} if null array input.
    4154     * @since 3.2
    4155     */
    4156    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
    4157        if (array == null) {
    4158            return null;
    4159        }
    4160        if (endIndex - startIndex <= 0) {
    4161            return EMPTY;
    4162        }
    4163        final StringBuilder stringBuilder = new StringBuilder();
    4164        for (int i = startIndex; i < endIndex; i++) {
    4165            stringBuilder
    4166                    .append(array[i])
    4167                    .append(delimiter);
    4168        }
    4169        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4170    }
    4171
    4172    /**
    4173     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4174     *
    4175     * <p>
    4176     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4177     * by empty strings.
    4178     * </p>
    4179     *
    4180     * <pre>
    4181     * StringUtils.join(null, *)          = null
    4182     * StringUtils.join([], *)            = ""
    4183     * StringUtils.join([null], *)        = ""
    4184     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4185     * StringUtils.join([1, 2, 3], null)  = "123"
    4186     * </pre>
    4187     *
    4188     * @param array
    4189     *            the array of values to join together, may be null.
    4190     * @param separator
    4191     *            the separator character to use.
    4192     * @return the joined String, {@code null} if null array input.
    4193     * @since 3.2
    4194     */
    4195    public static String join(final int[] array, final char separator) {
    4196        if (array == null) {
    4197            return null;
    4198        }
    4199        return join(array, separator, 0, array.length);
    4200    }
    4201
    4202    /**
    4203     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4204     *
    4205     * <p>
    4206     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4207     * by empty strings.
    4208     * </p>
    4209     *
    4210     * <pre>
    4211     * StringUtils.join(null, *)          = null
    4212     * StringUtils.join([], *)            = ""
    4213     * StringUtils.join([null], *)        = ""
    4214     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4215     * StringUtils.join([1, 2, 3], null)  = "123"
    4216     * </pre>
    4217     *
    4218     * @param array
    4219     *            the array of values to join together, may be null.
    4220     * @param delimiter
    4221     *            the separator character to use.
    4222     * @param startIndex
    4223     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4224     *            array.
    4225     * @param endIndex
    4226     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4227     *            the array.
    4228     * @return the joined String, {@code null} if null array input.
    4229     * @since 3.2
    4230     */
    4231    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
    4232        if (array == null) {
    4233            return null;
    4234        }
    4235        if (endIndex - startIndex <= 0) {
    4236            return EMPTY;
    4237        }
    4238        final StringBuilder stringBuilder = new StringBuilder();
    4239        for (int i = startIndex; i < endIndex; i++) {
    4240            stringBuilder
    4241                    .append(array[i])
    4242                    .append(delimiter);
    4243        }
    4244        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4245    }
    4246
    4247    /**
    4248     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
    4249     *
    4250     * <p>
    4251     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
    4252     * </p>
    4253     *
    4254     * <p>
    4255     * See the examples here: {@link #join(Object[],char)}.
    4256     * </p>
    4257     *
    4258     * @param iterable  the {@link Iterable} providing the values to join together, may be null.
    4259     * @param separator the separator character to use.
    4260     * @return the joined String, {@code null} if null iterator input.
    4261     * @since 2.3
    4262     */
    4263    public static String join(final Iterable<?> iterable, final char separator) {
    4264        return iterable != null ? join(iterable.iterator(), separator) : null;
    4265    }
    4266
    4267    /**
    4268     * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
    4269     *
    4270     * <p>
    4271     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
    4272     * </p>
    4273     *
    4274     * <p>
    4275     * See the examples here: {@link #join(Object[],String)}.
    4276     * </p>
    4277     *
    4278     * @param iterable  the {@link Iterable} providing the values to join together, may be null.
    4279     * @param separator the separator character to use, null treated as "".
    4280     * @return the joined String, {@code null} if null iterator input.
    4281     * @since 2.3
    4282     */
    4283    public static String join(final Iterable<?> iterable, final String separator) {
    4284        return iterable != null ? join(iterable.iterator(), separator) : null;
    4285    }
    4286
    4287    /**
    4288     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
    4289     *
    4290     * <p>
    4291     * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
    4292     * </p>
    4293     *
    4294     * <p>
    4295     * See the examples here: {@link #join(Object[],char)}.
    4296     * </p>
    4297     *
    4298     * @param iterator  the {@link Iterator} of values to join together, may be null.
    4299     * @param separator the separator character to use.
    4300     * @return the joined String, {@code null} if null iterator input.
    4301     * @since 2.0
    4302     */
    4303    public static String join(final Iterator<?> iterator, final char separator) {
    4304        // handle null, zero and one elements before building a buffer
    4305        if (iterator == null) {
    4306            return null;
    4307        }
    4308        if (!iterator.hasNext()) {
    4309            return EMPTY;
    4310        }
    4311        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
    4312    }
    4313
    4314    /**
    4315     * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
    4316     *
    4317     * <p>
    4318     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
    4319     * </p>
    4320     *
    4321     * <p>
    4322     * See the examples here: {@link #join(Object[],String)}.
    4323     * </p>
    4324     *
    4325     * @param iterator  the {@link Iterator} of values to join together, may be null.
    4326     * @param separator the separator character to use, null treated as "".
    4327     * @return the joined String, {@code null} if null iterator input.
    4328     */
    4329    public static String join(final Iterator<?> iterator, final String separator) {
    4330        // handle null, zero and one elements before building a buffer
    4331        if (iterator == null) {
    4332            return null;
    4333        }
    4334        if (!iterator.hasNext()) {
    4335            return EMPTY;
    4336        }
    4337        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
    4338    }
    4339
    4340    /**
    4341     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
    4342     *
    4343     * <p>
    4344     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
    4345     * </p>
    4346     *
    4347     * <pre>
    4348     * StringUtils.join(null, *)               = null
    4349     * StringUtils.join([], *)                 = ""
    4350     * StringUtils.join([null], *)             = ""
    4351     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4352     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4353     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4354     * </pre>
    4355     *
    4356     * @param list       the {@link List} of values to join together, may be null.
    4357     * @param separator  the separator character to use.
    4358     * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the list.
    4359     * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the list.
    4360     * @return the joined String, {@code null} if null list input.
    4361     * @since 3.8
    4362     */
    4363    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
    4364        if (list == null) {
    4365            return null;
    4366        }
    4367        final int noOfItems = endIndex - startIndex;
    4368        if (noOfItems <= 0) {
    4369            return EMPTY;
    4370        }
    4371        final List<?> subList = list.subList(startIndex, endIndex);
    4372        return join(subList.iterator(), separator);
    4373    }
    4374
    4375    /**
    4376     * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
    4377     *
    4378     * <p>
    4379     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
    4380     * </p>
    4381     *
    4382     * <pre>
    4383     * StringUtils.join(null, *)               = null
    4384     * StringUtils.join([], *)                 = ""
    4385     * StringUtils.join([null], *)             = ""
    4386     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4387     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4388     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4389     * </pre>
    4390     *
    4391     * @param list       the {@link List} of values to join together, may be null.
    4392     * @param separator  the separator character to use.
    4393     * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the list.
    4394     * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the list.
    4395     * @return the joined String, {@code null} if null list input.
    4396     * @since 3.8
    4397     */
    4398    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
    4399        if (list == null) {
    4400            return null;
    4401        }
    4402        final int noOfItems = endIndex - startIndex;
    4403        if (noOfItems <= 0) {
    4404            return EMPTY;
    4405        }
    4406        final List<?> subList = list.subList(startIndex, endIndex);
    4407        return join(subList.iterator(), separator);
    4408    }
    4409
    4410    /**
    4411     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4412     *
    4413     * <p>
    4414     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4415     * by empty strings.
    4416     * </p>
    4417     *
    4418     * <pre>
    4419     * StringUtils.join(null, *)               = null
    4420     * StringUtils.join([], *)                 = ""
    4421     * StringUtils.join([null], *)             = ""
    4422     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4423     * StringUtils.join([1, 2, 3], null) = "123"
    4424     * </pre>
    4425     *
    4426     * @param array
    4427     *            the array of values to join together, may be null.
    4428     * @param separator
    4429     *            the separator character to use.
    4430     * @return the joined String, {@code null} if null array input.
    4431     * @since 3.2
    4432     */
    4433    public static String join(final long[] array, final char separator) {
    4434        if (array == null) {
    4435            return null;
    4436        }
    4437        return join(array, separator, 0, array.length);
    4438    }
    4439
    4440    /**
    4441     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4442     *
    4443     * <p>
    4444     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4445     * by empty strings.
    4446     * </p>
    4447     *
    4448     * <pre>
    4449     * StringUtils.join(null, *)               = null
    4450     * StringUtils.join([], *)                 = ""
    4451     * StringUtils.join([null], *)             = ""
    4452     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4453     * StringUtils.join([1, 2, 3], null) = "123"
    4454     * </pre>
    4455     *
    4456     * @param array
    4457     *            the array of values to join together, may be null.
    4458     * @param delimiter
    4459     *            the separator character to use.
    4460     * @param startIndex
    4461     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4462     *            array.
    4463     * @param endIndex
    4464     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4465     *            the array.
    4466     * @return the joined String, {@code null} if null array input.
    4467     * @since 3.2
    4468     */
    4469    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
    4470        if (array == null) {
    4471            return null;
    4472        }
    4473        if (endIndex - startIndex <= 0) {
    4474            return EMPTY;
    4475        }
    4476        final StringBuilder stringBuilder = new StringBuilder();
    4477        for (int i = startIndex; i < endIndex; i++) {
    4478            stringBuilder
    4479                    .append(array[i])
    4480                    .append(delimiter);
    4481        }
    4482        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4483    }
    4484
    4485    /**
    4486     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4487     *
    4488     * <p>
    4489     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
    4490     * </p>
    4491     *
    4492     * <pre>
    4493     * StringUtils.join(null, *)               = null
    4494     * StringUtils.join([], *)                 = ""
    4495     * StringUtils.join([null], *)             = ""
    4496     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4497     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4498     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4499     * </pre>
    4500     *
    4501     * @param array     the array of values to join together, may be null.
    4502     * @param delimiter the separator character to use.
    4503     * @return the joined String, {@code null} if null array input.
    4504     * @since 2.0
    4505     */
    4506    public static String join(final Object[] array, final char delimiter) {
    4507        if (array == null) {
    4508            return null;
    4509        }
    4510        return join(array, delimiter, 0, array.length);
    4511    }
    4512
    4513    /**
    4514     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4515     *
    4516     * <p>
    4517     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
    4518     * </p>
    4519     *
    4520     * <pre>
    4521     * StringUtils.join(null, *)               = null
    4522     * StringUtils.join([], *)                 = ""
    4523     * StringUtils.join([null], *)             = ""
    4524     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4525     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4526     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4527     * </pre>
    4528     *
    4529     * @param array      the array of values to join together, may be null.
    4530     * @param delimiter  the separator character to use.
    4531     * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the array.
    4532     * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the array.
    4533     * @return the joined String, {@code null} if null array input.
    4534     * @since 2.0
    4535     */
    4536    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
    4537        return join(array, String.valueOf(delimiter), startIndex, endIndex);
    4538    }
    4539
    4540    /**
    4541     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4542     *
    4543     * <p>
    4544     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
    4545     * array are represented by empty strings.
    4546     * </p>
    4547     *
    4548     * <pre>
    4549     * StringUtils.join(null, *)                = null
    4550     * StringUtils.join([], *)                  = ""
    4551     * StringUtils.join([null], *)              = ""
    4552     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    4553     * StringUtils.join(["a", "b", "c"], null)  = "abc"
    4554     * StringUtils.join(["a", "b", "c"], "")    = "abc"
    4555     * StringUtils.join([null, "", "a"], ',')   = ",,a"
    4556     * </pre>
    4557     *
    4558     * @param array     the array of values to join together, may be null.
    4559     * @param delimiter the separator character to use, null treated as "".
    4560     * @return the joined String, {@code null} if null array input.
    4561     */
    4562    public static String join(final Object[] array, final String delimiter) {
    4563        return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
    4564    }
    4565
    4566    /**
    4567     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4568     *
    4569     * <p>
    4570     * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
    4571     * array are represented by empty strings.
    4572     * </p>
    4573     *
    4574     * <pre>
    4575     * StringUtils.join(null, *, *, *)                = null
    4576     * StringUtils.join([], *, *, *)                  = ""
    4577     * StringUtils.join([null], *, *, *)              = ""
    4578     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
    4579     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
    4580     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
    4581     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
    4582     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
    4583     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
    4584     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
    4585     * </pre>
    4586     *
    4587     * @param array      the array of values to join together, may be null.
    4588     * @param delimiter  the separator character to use, null treated as "".
    4589     * @param startIndex the first index to start joining from.
    4590     * @param endIndex   the index to stop joining from (exclusive).
    4591     * @return the joined String, {@code null} if null array input; or the empty string if {@code endIndex - startIndex <= 0}. The number of joined entries is
    4592     *         given by {@code endIndex - startIndex}.
    4593     * @throws ArrayIndexOutOfBoundsException ife<br>
    4594     *                                        {@code startIndex < 0} or <br>
    4595     *                                        {@code startIndex >= array.length()} or <br>
    4596     *                                        {@code endIndex < 0} or <br>
    4597     *                                        {@code endIndex > array.length()}
    4598     */
    4599    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
    4600        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
    4601                .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
    4602    }
    4603
    4604    /**
    4605     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4606     *
    4607     * <p>
    4608     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4609     * by empty strings.
    4610     * </p>
    4611     *
    4612     * <pre>
    4613     * StringUtils.join(null, *)          = null
    4614     * StringUtils.join([], *)            = ""
    4615     * StringUtils.join([null], *)        = ""
    4616     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4617     * StringUtils.join([1, 2, 3], null)  = "123"
    4618     * </pre>
    4619     *
    4620     * @param array
    4621     *            the array of values to join together, may be null.
    4622     * @param delimiter
    4623     *            the separator character to use.
    4624     * @return the joined String, {@code null} if null array input.
    4625     * @since 3.2
    4626     */
    4627    public static String join(final short[] array, final char delimiter) {
    4628        if (array == null) {
    4629            return null;
    4630        }
    4631        return join(array, delimiter, 0, array.length);
    4632    }
    4633
    4634    /**
    4635     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4636     *
    4637     * <p>
    4638     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4639     * by empty strings.
    4640     * </p>
    4641     *
    4642     * <pre>
    4643     * StringUtils.join(null, *)          = null
    4644     * StringUtils.join([], *)            = ""
    4645     * StringUtils.join([null], *)        = ""
    4646     * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
    4647     * StringUtils.join([1, 2, 3], null)  = "123"
    4648     * </pre>
    4649     *
    4650     * @param array
    4651     *            the array of values to join together, may be null.
    4652     * @param delimiter
    4653     *            the separator character to use.
    4654     * @param startIndex
    4655     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4656     *            array.
    4657     * @param endIndex
    4658     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4659     *            the array.
    4660     * @return the joined String, {@code null} if null array input.
    4661     * @since 3.2
    4662     */
    4663    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
    4664        if (array == null) {
    4665            return null;
    4666        }
    4667        if (endIndex - startIndex <= 0) {
    4668            return EMPTY;
    4669        }
    4670        final StringBuilder stringBuilder = new StringBuilder();
    4671        for (int i = startIndex; i < endIndex; i++) {
    4672            stringBuilder
    4673                    .append(array[i])
    4674                    .append(delimiter);
    4675        }
    4676        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4677    }
    4678
    4679    /**
    4680     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4681     *
    4682     * <p>
    4683     * No separator is added to the joined String. Null objects or empty strings within the array are represented by empty strings.
    4684     * </p>
    4685     *
    4686     * <pre>
    4687     * StringUtils.join(null)            = null
    4688     * StringUtils.join([])              = ""
    4689     * StringUtils.join([null])          = ""
    4690     * StringUtils.join(["a", "b", "c"]) = "abc"
    4691     * StringUtils.join([null, "", "a"]) = "a"
    4692     * </pre>
    4693     *
    4694     * @param <T>      the specific type of values to join together.
    4695     * @param elements the values to join together, may be null.
    4696     * @return the joined String, {@code null} if null array input.
    4697     * @since 2.0
    4698     * @since 3.0 Changed signature to use varargs
    4699     */
    4700    @SafeVarargs
    4701    public static <T> String join(final T... elements) {
    4702        return join(elements, null);
    4703    }
    4704
    4705    /**
    4706     * Joins the elements of the provided varargs into a single String containing the provided elements.
    4707     *
    4708     * <p>
    4709     * No delimiter is added before or after the list. {@code null} elements and separator are treated as empty Strings ("").
    4710     * </p>
    4711     *
    4712     * <pre>
    4713     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
    4714     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
    4715     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
    4716     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
    4717     * </pre>
    4718     *
    4719     * @param delimiter the separator character to use, null treated as "".
    4720     * @param array     the varargs providing the values to join together. {@code null} elements are treated as "".
    4721     * @return the joined String.
    4722     * @throws IllegalArgumentException if a null varargs is provided.
    4723     * @since 3.5
    4724     */
    4725    public static String joinWith(final String delimiter, final Object... array) {
    4726        if (array == null) {
    4727            throw new IllegalArgumentException("Object varargs must not be null");
    4728        }
    4729        return join(array, delimiter);
    4730    }
    4731
    4732    /**
    4733     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String)} if possible.
    4734     *
    4735     * <p>
    4736     * A {@code null} CharSequence will return {@code -1}.
    4737     * </p>
    4738     *
    4739     * <pre>
    4740     * StringUtils.lastIndexOf(null, *)          = -1
    4741     * StringUtils.lastIndexOf(*, null)          = -1
    4742     * StringUtils.lastIndexOf("", "")           = 0
    4743     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    4744     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    4745     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    4746     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    4747     * </pre>
    4748     *
    4749     * @param seq       the CharSequence to check, may be null.
    4750     * @param searchSeq the CharSequence to find, may be null.
    4751     * @return the last index of the search String, -1 if no match or {@code null} string input.
    4752     * @since 2.0
    4753     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
    4754     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}
    4755     */
    4756    @Deprecated
    4757    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
    4758        return Strings.CS.lastIndexOf(seq, searchSeq);
    4759    }
    4760
    4761    /**
    4762     * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String, int)} if possible.
    4763     *
    4764     * <p>
    4765     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
    4766     * the start position is negative. A start position greater than the string length searches the whole string. The search starts at the startPos and works
    4767     * backwards; matches starting after the start position are ignored.
    4768     * </p>
    4769     *
    4770     * <pre>
    4771     * StringUtils.lastIndexOf(null, *, *)          = -1
    4772     * StringUtils.lastIndexOf(*, null, *)          = -1
    4773     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    4774     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    4775     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    4776     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    4777     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    4778     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    4779     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    4780     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
    4781     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
    4782     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
    4783     * </pre>
    4784     *
    4785     * @param seq       the CharSequence to check, may be null.
    4786     * @param searchSeq the CharSequence to find, may be null.
    4787     * @param startPos  the start position, negative treated as zero.
    4788     * @return the last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} string input.
    4789     * @since 2.0
    4790     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
    4791     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}
    4792     */
    4793    @Deprecated
    4794    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    4795        return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
    4796    }
    4797
    4798    /**
    4799     * Returns the index within {@code seq} of the last occurrence of the specified character. For values of {@code searchChar} in the range from 0 to 0xFFFF
    4800     * (inclusive), the index (in Unicode code units) returned is the largest value <em>k</em> such that:
    4801     *
    4802     * <pre>
    4803     * this.charAt(<em>k</em>) == searchChar
    4804     * </pre>
    4805     *
    4806     * <p>
    4807     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
    4808     * </p>
    4809     *
    4810     * <pre>
    4811     * this.codePointAt(<em>k</em>) == searchChar
    4812     * </pre>
    4813     *
    4814     * <p>
    4815     * is true. In either case, if no such character occurs in this string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4816     * {@link CharSequence} will return {@code -1}. The {@code seq} {@link CharSequence} object is searched backwards starting at the last character.
    4817     * </p>
    4818     *
    4819     * <pre>
    4820     * StringUtils.lastIndexOf(null, *)         = -1
    4821     * StringUtils.lastIndexOf("", *)           = -1
    4822     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    4823     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    4824     * </pre>
    4825     *
    4826     * @param seq        the {@link CharSequence} to check, may be null.
    4827     * @param searchChar the character to find.
    4828     * @return the last index of the search character, -1 if no match or {@code null} string input.
    4829     * @since 2.0
    4830     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
    4831     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    4832     */
    4833    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
    4834        if (isEmpty(seq)) {
    4835            return INDEX_NOT_FOUND;
    4836        }
    4837        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
    4838    }
    4839
    4840    /**
    4841     * Returns the index within {@code seq} of the last occurrence of the specified character, searching backward starting at the specified index. For values of
    4842     * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index returned is the largest value <em>k</em> such that:
    4843     *
    4844     * <pre>
    4845     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
    4846     * </pre>
    4847     *
    4848     * <p>
    4849     * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
    4850     * </p>
    4851     *
    4852     * <pre>
    4853     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
    4854     * </pre>
    4855     *
    4856     * <p>
    4857     * is true. In either case, if no such character occurs in {@code seq} at or before position {@code startPos}, then {@code -1} is returned. Furthermore, a
    4858     * {@code null} or empty ("") {@link CharSequence} will return {@code -1}. A start position greater than the string length searches the whole string. The
    4859     * search starts at the {@code startPos} and works backwards; matches starting after the start position are ignored.
    4860     * </p>
    4861     *
    4862     * <p>
    4863     * All indices are specified in {@code char} values (Unicode code units).
    4864     * </p>
    4865     *
    4866     * <pre>
    4867     * StringUtils.lastIndexOf(null, *, *)          = -1
    4868     * StringUtils.lastIndexOf("", *,  *)           = -1
    4869     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    4870     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    4871     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    4872     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    4873     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    4874     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    4875     * </pre>
    4876     *
    4877     * @param seq        the CharSequence to check, may be null.
    4878     * @param searchChar the character to find.
    4879     * @param startPos   the start position.
    4880     * @return the last index of the search character (always &le; startPos), -1 if no match or {@code null} string input.
    4881     * @since 2.0
    4882     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
    4883     */
    4884    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
    4885        if (isEmpty(seq)) {
    4886            return INDEX_NOT_FOUND;
    4887        }
    4888        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
    4889    }
    4890
    4891    /**
    4892     * Finds the latest index of any substring in a set of potential substrings.
    4893     *
    4894     * <p>
    4895     * A {@code null} CharSequence will return {@code -1}. A {@code null} search array will return {@code -1}. A {@code null} or zero length search array entry
    4896     * will be ignored, but a search array containing "" will return the length of {@code str} if {@code str} is not null. This method uses
    4897     * {@link String#indexOf(String)} if possible
    4898     * </p>
    4899     *
    4900     * <pre>
    4901     * StringUtils.lastIndexOfAny(null, *)                    = -1
    4902     * StringUtils.lastIndexOfAny(*, null)                    = -1
    4903     * StringUtils.lastIndexOfAny(*, [])                      = -1
    4904     * StringUtils.lastIndexOfAny(*, [null])                  = -1
    4905     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
    4906     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
    4907     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    4908     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    4909     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
    4910     * </pre>
    4911     *
    4912     * @param str        the CharSequence to check, may be null.
    4913     * @param searchStrs the CharSequences to search for, may be null.
    4914     * @return the last index of any of the CharSequences, -1 if no match.
    4915     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
    4916     */
    4917    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    4918        if (str == null || searchStrs == null) {
    4919            return INDEX_NOT_FOUND;
    4920        }
    4921        int ret = INDEX_NOT_FOUND;
    4922        int tmp;
    4923        for (final CharSequence search : searchStrs) {
    4924            if (search == null) {
    4925                continue;
    4926            }
    4927            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
    4928            if (tmp > ret) {
    4929                ret = tmp;
    4930            }
    4931        }
    4932        return ret;
    4933    }
    4934
    4935    /**
    4936     * Case in-sensitive find of the last index within a CharSequence.
    4937     *
    4938     * <p>
    4939     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
    4940     * the start position is negative. A start position greater than the string length searches the whole string.
    4941     * </p>
    4942     *
    4943     * <pre>
    4944     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    4945     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    4946     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    4947     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    4948     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    4949     * </pre>
    4950     *
    4951     * @param str       the CharSequence to check, may be null.
    4952     * @param searchStr the CharSequence to find, may be null.
    4953     * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
    4954     * @since 2.5
    4955     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
    4956     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}
    4957     */
    4958    @Deprecated
    4959    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    4960        return Strings.CI.lastIndexOf(str, searchStr);
    4961    }
    4962
    4963    /**
    4964     * Case in-sensitive find of the last index within a CharSequence from the specified position.
    4965     *
    4966     * <p>
    4967     * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
    4968     * the start position is negative. A start position greater than the string length searches the whole string. The search starts at the startPos and works
    4969     * backwards; matches starting after the start position are ignored.
    4970     * </p>
    4971     *
    4972     * <pre>
    4973     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    4974     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    4975     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    4976     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    4977     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    4978     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    4979     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    4980     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    4981     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    4982     * </pre>
    4983     *
    4984     * @param str       the CharSequence to check, may be null.
    4985     * @param searchStr the CharSequence to find, may be null.
    4986     * @param startPos  the start position.
    4987     * @return the last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} input.
    4988     * @since 2.5
    4989     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
    4990     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}
    4991     */
    4992    @Deprecated
    4993    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
    4994        return Strings.CI.lastIndexOf(str, searchStr, startPos);
    4995    }
    4996
    4997    /**
    4998     * Finds the n-th last index within a String, handling {@code null}. This method uses {@link String#lastIndexOf(String)}.
    4999     *
    5000     * <p>
    5001     * A {@code null} String will return {@code -1}.
    5002     * </p>
    5003     *
    5004     * <pre>
    5005     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    5006     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    5007     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    5008     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    5009     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    5010     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    5011     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    5012     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    5013     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    5014     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    5015     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    5016     * </pre>
    5017     *
    5018     * <p>
    5019     * Note that 'tail(CharSequence str, int n)' may be implemented as:
    5020     * </p>
    5021     *
    5022     * <pre>
    5023     * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    5024     * </pre>
    5025     *
    5026     * @param str       the CharSequence to check, may be null.
    5027     * @param searchStr the CharSequence to find, may be null.
    5028     * @param ordinal   the n-th last {@code searchStr} to find.
    5029     * @return the n-th last index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
    5030     * @since 2.5
    5031     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
    5032     */
    5033    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5034        return ordinalIndexOf(str, searchStr, ordinal, true);
    5035    }
    5036
    5037    /**
    5038     * Gets the leftmost {@code len} characters of a String.
    5039     *
    5040     * <p>
    5041     * If {@code len} characters are not available, or the String is {@code null}, the String will be returned without an exception. An empty String is returned
    5042     * if len is negative.
    5043     * </p>
    5044     *
    5045     * <pre>
    5046     * StringUtils.left(null, *)    = null
    5047     * StringUtils.left(*, -ve)     = ""
    5048     * StringUtils.left("", *)      = ""
    5049     * StringUtils.left("abc", 0)   = ""
    5050     * StringUtils.left("abc", 2)   = "ab"
    5051     * StringUtils.left("abc", 4)   = "abc"
    5052     * </pre>
    5053     *
    5054     * @param str the String to get the leftmost characters from, may be null.
    5055     * @param len the length of the required String.
    5056     * @return the leftmost characters, {@code null} if null String input.
    5057     */
    5058    public static String left(final String str, final int len) {
    5059        if (str == null) {
    5060            return null;
    5061        }
    5062        if (len < 0) {
    5063            return EMPTY;
    5064        }
    5065        if (str.length() <= len) {
    5066            return str;
    5067        }
    5068        return str.substring(0, len);
    5069    }
    5070
    5071    /**
    5072     * Left pad a String with spaces (' ').
    5073     *
    5074     * <p>
    5075     * The String is padded to the size of {@code size}.
    5076     * </p>
    5077     *
    5078     * <pre>
    5079     * StringUtils.leftPad(null, *)   = null
    5080     * StringUtils.leftPad("", 3)     = "   "
    5081     * StringUtils.leftPad("bat", 3)  = "bat"
    5082     * StringUtils.leftPad("bat", 5)  = "  bat"
    5083     * StringUtils.leftPad("bat", 1)  = "bat"
    5084     * StringUtils.leftPad("bat", -1) = "bat"
    5085     * </pre>
    5086     *
    5087     * @param str  the String to pad out, may be null.
    5088     * @param size the size to pad to.
    5089     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
    5090     */
    5091    public static String leftPad(final String str, final int size) {
    5092        return leftPad(str, size, ' ');
    5093    }
    5094
    5095    /**
    5096     * Left pad a String with a specified character.
    5097     *
    5098     * <p>
    5099     * Pad to a size of {@code size}.
    5100     * </p>
    5101     *
    5102     * <pre>
    5103     * StringUtils.leftPad(null, *, *)     = null
    5104     * StringUtils.leftPad("", 3, 'z')     = "zzz"
    5105     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    5106     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    5107     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    5108     * StringUtils.leftPad("bat", -1, 'z') = "bat"
    5109     * </pre>
    5110     *
    5111     * @param str     the String to pad out, may be null.
    5112     * @param size    the size to pad to.
    5113     * @param padChar the character to pad with.
    5114     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
    5115     * @since 2.0
    5116     */
    5117    public static String leftPad(final String str, final int size, final char padChar) {
    5118        if (str == null) {
    5119            return null;
    5120        }
    5121        final int pads = size - str.length();
    5122        if (pads <= 0) {
    5123            return str; // returns original String when possible
    5124        }
    5125        if (pads > PAD_LIMIT) {
    5126            return leftPad(str, size, String.valueOf(padChar));
    5127        }
    5128        return repeat(padChar, pads).concat(str);
    5129    }
    5130
    5131    /**
    5132     * Left pad a String with a specified String.
    5133     *
    5134     * <p>
    5135     * Pad to a size of {@code size}.
    5136     * </p>
    5137     *
    5138     * <pre>
    5139     * StringUtils.leftPad(null, *, *)      = null
    5140     * StringUtils.leftPad("", 3, "z")      = "zzz"
    5141     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    5142     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    5143     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    5144     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    5145     * StringUtils.leftPad("bat", -1, "yz") = "bat"
    5146     * StringUtils.leftPad("bat", 5, null)  = "  bat"
    5147     * StringUtils.leftPad("bat", 5, "")    = "  bat"
    5148     * </pre>
    5149     *
    5150     * @param str    the String to pad out, may be null.
    5151     * @param size   the size to pad to.
    5152     * @param padStr the String to pad with, null or empty treated as single space.
    5153     * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
    5154     */
    5155    public static String leftPad(final String str, final int size, String padStr) {
    5156        if (str == null) {
    5157            return null;
    5158        }
    5159        if (isEmpty(padStr)) {
    5160            padStr = SPACE;
    5161        }
    5162        final int padLen = padStr.length();
    5163        final int strLen = str.length();
    5164        final int pads = size - strLen;
    5165        if (pads <= 0) {
    5166            return str; // returns original String when possible
    5167        }
    5168        if (padLen == 1 && pads <= PAD_LIMIT) {
    5169            return leftPad(str, size, padStr.charAt(0));
    5170        }
    5171        if (pads == padLen) {
    5172            return padStr.concat(str);
    5173        }
    5174        if (pads < padLen) {
    5175            return padStr.substring(0, pads).concat(str);
    5176        }
    5177        final char[] padding = new char[pads];
    5178        final char[] padChars = padStr.toCharArray();
    5179        for (int i = 0; i < pads; i++) {
    5180            padding[i] = padChars[i % padLen];
    5181        }
    5182        return new String(padding).concat(str);
    5183    }
    5184
    5185    /**
    5186     * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}.
    5187     *
    5188     * @param cs a CharSequence or {@code null}.
    5189     * @return CharSequence length or {@code 0} if the CharSequence is {@code null}.
    5190     * @since 2.4
    5191     * @since 3.0 Changed signature from length(String) to length(CharSequence)
    5192     */
    5193    public static int length(final CharSequence cs) {
    5194        return cs == null ? 0 : cs.length();
    5195    }
    5196
    5197    /**
    5198     * Converts a String to lower case as per {@link String#toLowerCase()}.
    5199     *
    5200     * <p>
    5201     * A {@code null} input String returns {@code null}.
    5202     * </p>
    5203     *
    5204     * <pre>
    5205     * StringUtils.lowerCase(null)  = null
    5206     * StringUtils.lowerCase("")    = ""
    5207     * StringUtils.lowerCase("aBc") = "abc"
    5208     * </pre>
    5209     *
    5210     * <p>
    5211     * <strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, the result of this method is affected by the current locale.
    5212     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} should be used with a specific locale (e.g.
    5213     * {@link Locale#ENGLISH}).
    5214     * </p>
    5215     *
    5216     * @param str the String to lower case, may be null.
    5217     * @return the lower cased String, {@code null} if null String input.
    5218     */
    5219    public static String lowerCase(final String str) {
    5220        if (str == null) {
    5221            return null;
    5222        }
    5223        return str.toLowerCase();
    5224    }
    5225
    5226    /**
    5227     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
    5228     *
    5229     * <p>
    5230     * A {@code null} input String returns {@code null}.
    5231     * </p>
    5232     *
    5233     * <pre>
    5234     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    5235     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    5236     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    5237     * </pre>
    5238     *
    5239     * @param str    the String to lower case, may be null.
    5240     * @param locale the locale that defines the case transformation rules, must not be null.
    5241     * @return the lower cased String, {@code null} if null String input.
    5242     * @since 2.5
    5243     */
    5244    public static String lowerCase(final String str, final Locale locale) {
    5245        if (str == null) {
    5246            return null;
    5247        }
    5248        return str.toLowerCase(LocaleUtils.toLocale(locale));
    5249    }
    5250
    5251    private static int[] matches(final CharSequence first, final CharSequence second) {
    5252        final CharSequence max;
    5253        final CharSequence min;
    5254        if (first.length() > second.length()) {
    5255            max = first;
    5256            min = second;
    5257        } else {
    5258            max = second;
    5259            min = first;
    5260        }
    5261        final int range = Math.max(max.length() / 2 - 1, 0);
    5262        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
    5263        final boolean[] matchFlags = new boolean[max.length()];
    5264        int matches = 0;
    5265        for (int mi = 0; mi < min.length(); mi++) {
    5266            final char c1 = min.charAt(mi);
    5267            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
    5268                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
    5269                    matchIndexes[mi] = xi;
    5270                    matchFlags[xi] = true;
    5271                    matches++;
    5272                    break;
    5273                }
    5274            }
    5275        }
    5276        final char[] ms1 = new char[matches];
    5277        final char[] ms2 = new char[matches];
    5278        for (int i = 0, si = 0; i < min.length(); i++) {
    5279            if (matchIndexes[i] != -1) {
    5280                ms1[si] = min.charAt(i);
    5281                si++;
    5282            }
    5283        }
    5284        for (int i = 0, si = 0; i < max.length(); i++) {
    5285            if (matchFlags[i]) {
    5286                ms2[si] = max.charAt(i);
    5287                si++;
    5288            }
    5289        }
    5290        int transpositions = 0;
    5291        for (int mi = 0; mi < ms1.length; mi++) {
    5292            if (ms1[mi] != ms2[mi]) {
    5293                transpositions++;
    5294            }
    5295        }
    5296        int prefix = 0;
    5297        for (int mi = 0; mi < min.length(); mi++) {
    5298            if (first.charAt(mi) != second.charAt(mi)) {
    5299                break;
    5300            }
    5301            prefix++;
    5302        }
    5303        return new int[] { matches, transpositions / 2, prefix, max.length() };
    5304    }
    5305
    5306    /**
    5307     * Gets {@code len} characters from the middle of a String.
    5308     *
    5309     * <p>
    5310     * If {@code len} characters are not available, the remainder of the String will be returned without an exception. If the String is {@code null},
    5311     * {@code null} will be returned. An empty String is returned if len is negative or exceeds the length of {@code str}.
    5312     * </p>
    5313     *
    5314     * <pre>
    5315     * StringUtils.mid(null, *, *)    = null
    5316     * StringUtils.mid(*, *, -ve)     = ""
    5317     * StringUtils.mid("", 0, *)      = ""
    5318     * StringUtils.mid("abc", 0, 2)   = "ab"
    5319     * StringUtils.mid("abc", 0, 4)   = "abc"
    5320     * StringUtils.mid("abc", 2, 4)   = "c"
    5321     * StringUtils.mid("abc", 4, 2)   = ""
    5322     * StringUtils.mid("abc", -2, 2)  = "ab"
    5323     * </pre>
    5324     *
    5325     * @param str the String to get the characters from, may be null.
    5326     * @param pos the position to start from, negative treated as zero.
    5327     * @param len the length of the required String.
    5328     * @return the middle characters, {@code null} if null String input.
    5329     */
    5330    public static String mid(final String str, int pos, final int len) {
    5331        if (str == null) {
    5332            return null;
    5333        }
    5334        if (len < 0 || pos > str.length()) {
    5335            return EMPTY;
    5336        }
    5337        if (pos < 0) {
    5338            pos = 0;
    5339        }
    5340        if (str.length() <= pos + len) {
    5341            return str.substring(pos);
    5342        }
    5343        return str.substring(pos, pos + len);
    5344    }
    5345
    5346    /**
    5347     * Similar to <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize -space</a>
    5348     *
    5349     * <p>
    5350     * The function returns the argument string with whitespace normalized by using {@code {@link #trim(String)}} to remove leading and trailing whitespace and
    5351     * then replacing sequences of whitespace characters by a single space.
    5352     * </p>
    5353     * In XML Whitespace characters are the same as those allowed by the <a href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 |
    5354     * #x9 | #xD | #xA)+
    5355     * <p>
    5356     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
    5357     * </p>
    5358     * <p>
    5359     * For reference:
    5360     * </p>
    5361     * <ul>
    5362     * <li>\x0B = vertical tab</li>
    5363     * <li>\f = #xC = form feed</li>
    5364     * <li>#x20 = space</li>
    5365     * <li>#x9 = \t</li>
    5366     * <li>#xA = \n</li>
    5367     * <li>#xD = \r</li>
    5368     * </ul>
    5369     *
    5370     * <p>
    5371     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also normalize. Additionally {@code {@link
    5372     * #trim(String)}} removes control characters (char &lt;= 32) from both ends of this String.
    5373     * </p>
    5374     *
    5375     * @param str the source String to normalize whitespaces from, may be null.
    5376     * @return the modified string with whitespace normalized, {@code null} if null String input.
    5377     * @see Pattern
    5378     * @see #trim(String)
    5379     * @see <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
    5380     * @since 3.0
    5381     */
    5382    public static String normalizeSpace(final String str) {
    5383        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
    5384        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
    5385        if (isEmpty(str)) {
    5386            return str;
    5387        }
    5388        final int size = str.length();
    5389        final char[] newChars = new char[size];
    5390        int count = 0;
    5391        int whitespacesCount = 0;
    5392        boolean startWhitespaces = true;
    5393        for (int i = 0; i < size; i++) {
    5394            final char actualChar = str.charAt(i);
    5395            final boolean isWhitespace = Character.isWhitespace(actualChar);
    5396            if (isWhitespace) {
    5397                if (whitespacesCount == 0 && !startWhitespaces) {
    5398                    newChars[count++] = SPACE.charAt(0);
    5399                }
    5400                whitespacesCount++;
    5401            } else {
    5402                startWhitespaces = false;
    5403                newChars[count++] = actualChar == 160 ? 32 : actualChar;
    5404                whitespacesCount = 0;
    5405            }
    5406        }
    5407        if (startWhitespaces) {
    5408            return EMPTY;
    5409        }
    5410        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
    5411    }
    5412
    5413    /**
    5414     * Finds the n-th index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
    5415     * <p>
    5416     * <strong>Note:</strong> The code starts looking for a match at the start of the target, incrementing the starting index by one after each successful match
    5417     * (unless {@code searchStr} is an empty string in which case the position is never incremented and {@code 0} is returned immediately). This means that
    5418     * matches may overlap.
    5419     * </p>
    5420     * <p>
    5421     * A {@code null} CharSequence will return {@code -1}.
    5422     * </p>
    5423     *
    5424     * <pre>
    5425     * StringUtils.ordinalIndexOf(null, *, *)          = -1
    5426     * StringUtils.ordinalIndexOf(*, null, *)          = -1
    5427     * StringUtils.ordinalIndexOf("", "", *)           = 0
    5428     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    5429     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    5430     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    5431     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    5432     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    5433     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    5434     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    5435     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    5436     * </pre>
    5437     *
    5438     * <p>
    5439     * Matches may overlap:
    5440     * </p>
    5441     *
    5442     * <pre>
    5443     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
    5444     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
    5445     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
    5446     *
    5447     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
    5448     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
    5449     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
    5450     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
    5451     * </pre>
    5452     *
    5453     * <p>
    5454     * Note that 'head(CharSequence str, int n)' may be implemented as:
    5455     * </p>
    5456     *
    5457     * <pre>
    5458     * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    5459     * </pre>
    5460     *
    5461     * @param str       the CharSequence to check, may be null.
    5462     * @param searchStr the CharSequence to find, may be null.
    5463     * @param ordinal   the n-th {@code searchStr} to find.
    5464     * @return the n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
    5465     * @since 2.1
    5466     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
    5467     */
    5468    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5469        return ordinalIndexOf(str, searchStr, ordinal, false);
    5470    }
    5471
    5472    /**
    5473     * Finds the n-th index within a String, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
    5474     * <p>
    5475     * Note that matches may overlap
    5476     * <p>
    5477     *
    5478     * <p>
    5479     * A {@code null} CharSequence will return {@code -1}.
    5480     * </p>
    5481     *
    5482     * @param str       the CharSequence to check, may be null.
    5483     * @param searchStr the CharSequence to find, may be null.
    5484     * @param ordinal   the n-th {@code searchStr} to find, overlapping matches are allowed.
    5485     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf().
    5486     * @return the n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
    5487     */
    5488    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
    5489    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
    5490        if (str == null || searchStr == null || ordinal <= 0) {
    5491            return INDEX_NOT_FOUND;
    5492        }
    5493        if (searchStr.length() == 0) {
    5494            return lastIndex ? str.length() : 0;
    5495        }
    5496        int found = 0;
    5497        // set the initial index beyond the end of the string
    5498        // this is to allow for the initial index decrement/increment
    5499        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    5500        do {
    5501            if (lastIndex) {
    5502                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
    5503            } else {
    5504                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
    5505            }
    5506            if (index < 0) {
    5507                return index;
    5508            }
    5509            found++;
    5510        } while (found < ordinal);
    5511        return index;
    5512    }
    5513
    5514    /**
    5515     * Overlays part of a String with another String.
    5516     *
    5517     * <p>
    5518     * A {@code null} string input returns {@code null}. A negative index is treated as zero. An index greater than the string length is treated as the string
    5519     * length. The start index is always the smaller of the two indices.
    5520     * </p>
    5521     *
    5522     * <pre>
    5523     * StringUtils.overlay(null, *, *, *)            = null
    5524     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    5525     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    5526     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    5527     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    5528     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    5529     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    5530     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    5531     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    5532     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    5533     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    5534     * </pre>
    5535     *
    5536     * @param str     the String to do overlaying in, may be null.
    5537     * @param overlay the String to overlay, may be null.
    5538     * @param start   the position to start overlaying at.
    5539     * @param end     the position to stop overlaying before.
    5540     * @return overlayed String, {@code null} if null String input.
    5541     * @since 2.0
    5542     */
    5543    public static String overlay(final String str, String overlay, int start, int end) {
    5544        if (str == null) {
    5545            return null;
    5546        }
    5547        if (overlay == null) {
    5548            overlay = EMPTY;
    5549        }
    5550        final int len = str.length();
    5551        if (start < 0) {
    5552            start = 0;
    5553        }
    5554        if (start > len) {
    5555            start = len;
    5556        }
    5557        if (end < 0) {
    5558            end = 0;
    5559        }
    5560        if (end > len) {
    5561            end = len;
    5562        }
    5563        if (start > end) {
    5564            final int temp = start;
    5565            start = end;
    5566            end = temp;
    5567        }
    5568        return str.substring(0, start) + overlay + str.substring(end);
    5569    }
    5570
    5571    /**
    5572     * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
    5573     *
    5574     * <pre>
    5575     * StringUtils.prependIfMissing(null, null) = null
    5576     * StringUtils.prependIfMissing("abc", null) = "abc"
    5577     * StringUtils.prependIfMissing("", "xyz") = "xyz"
    5578     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
    5579     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
    5580     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
    5581     * </pre>
    5582     * <p>
    5583     * With additional prefixes,
    5584     * </p>
    5585     *
    5586     * <pre>
    5587     * StringUtils.prependIfMissing(null, null, null) = null
    5588     * StringUtils.prependIfMissing("abc", null, null) = "abc"
    5589     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
    5590     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5591     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
    5592     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
    5593     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
    5594     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
    5595     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
    5596     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
    5597     * </pre>
    5598     *
    5599     * @param str      The string.
    5600     * @param prefix   The prefix to prepend to the start of the string.
    5601     * @param prefixes Additional prefixes that are valid.
    5602     * @return A new String if prefix was prepended, the same string otherwise.
    5603     * @since 3.2
    5604     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
    5605     *             CharSequence...)}
    5606     */
    5607    @Deprecated
    5608    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5609        return Strings.CS.prependIfMissing(str, prefix, prefixes);
    5610    }
    5611
    5612    /**
    5613     * Prepends the prefix to the start of the string if the string does not already start, case-insensitive, with any of the prefixes.
    5614     *
    5615     * <pre>
    5616     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
    5617     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
    5618     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
    5619     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
    5620     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
    5621     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
    5622     * </pre>
    5623     * <p>
    5624     * With additional prefixes,
    5625     * </p>
    5626     *
    5627     * <pre>
    5628     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
    5629     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
    5630     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
    5631     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5632     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    5633     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
    5634     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
    5635     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
    5636     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
    5637     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
    5638     * </pre>
    5639     *
    5640     * @param str      The string.
    5641     * @param prefix   The prefix to prepend to the start of the string.
    5642     * @param prefixes Additional prefixes that are valid (optional).
    5643     * @return A new String if prefix was prepended, the same string otherwise.
    5644     * @since 3.2
    5645     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
    5646     *             CharSequence...)}
    5647     */
    5648    @Deprecated
    5649    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5650        return Strings.CI.prependIfMissing(str, prefix, prefixes);
    5651    }
    5652
    5653    /**
    5654     * Removes all occurrences of a character from within the source string.
    5655     *
    5656     * <p>
    5657     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string.
    5658     * </p>
    5659     *
    5660     * <pre>
    5661     * StringUtils.remove(null, *)       = null
    5662     * StringUtils.remove("", *)         = ""
    5663     * StringUtils.remove("queued", 'u') = "qeed"
    5664     * StringUtils.remove("queued", 'z') = "queued"
    5665     * </pre>
    5666     *
    5667     * @param str    the source String to search, may be null.
    5668     * @param remove the char to search for and remove, may be null.
    5669     * @return the substring with the char removed if found, {@code null} if null String input.
    5670     * @since 2.1
    5671     */
    5672    public static String remove(final String str, final char remove) {
    5673        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    5674            return str;
    5675        }
    5676        final char[] chars = str.toCharArray();
    5677        int pos = 0;
    5678        for (int i = 0; i < chars.length; i++) {
    5679            if (chars[i] != remove) {
    5680                chars[pos++] = chars[i];
    5681            }
    5682        }
    5683        return new String(chars, 0, pos);
    5684    }
    5685
    5686    /**
    5687     * Removes all occurrences of a substring from within the source string.
    5688     *
    5689     * <p>
    5690     * 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
    5691     * the source string. An empty ("") remove string will return the source string.
    5692     * </p>
    5693     *
    5694     * <pre>
    5695     * StringUtils.remove(null, *)        = null
    5696     * StringUtils.remove("", *)          = ""
    5697     * StringUtils.remove(*, null)        = *
    5698     * StringUtils.remove(*, "")          = *
    5699     * StringUtils.remove("queued", "ue") = "qd"
    5700     * StringUtils.remove("queued", "zz") = "queued"
    5701     * </pre>
    5702     *
    5703     * @param str    the source String to search, may be null.
    5704     * @param remove the String to search for and remove, may be null.
    5705     * @return the substring with the string removed if found, {@code null} if null String input.
    5706     * @since 2.1
    5707     * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}
    5708     */
    5709    @Deprecated
    5710    public static String remove(final String str, final String remove) {
    5711        return Strings.CS.remove(str, remove);
    5712    }
    5713
    5714    /**
    5715     * Removes each substring of the text String that matches the given regular expression.
    5716     *
    5717     * This method is a {@code null} safe equivalent to:
    5718     * <ul>
    5719     * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
    5720     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
    5721     * </ul>
    5722     *
    5723     * <p>
    5724     * A {@code null} reference passed to this method is a no-op.
    5725     * </p>
    5726     *
    5727     * <p>
    5728     * Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option
    5729     * prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
    5730     * </p>
    5731     *
    5732     * <pre>{@code
    5733     * StringUtils.removeAll(null, *)      = null
    5734     * StringUtils.removeAll("any", (String) null)  = "any"
    5735     * StringUtils.removeAll("any", "")    = "any"
    5736     * StringUtils.removeAll("any", ".*")  = ""
    5737     * StringUtils.removeAll("any", ".+")  = ""
    5738     * StringUtils.removeAll("abc", ".?")  = ""
    5739     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
    5740     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
    5741     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
    5742     * }</pre>
    5743     *
    5744     * @param text  text to remove from, may be null.
    5745     * @param regex the regular expression to which this string is to be matched.
    5746     * @return the text with any removes processed, {@code null} if null String input.
    5747     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
    5748     * @see #replaceAll(String, String, String)
    5749     * @see #removePattern(String, String)
    5750     * @see String#replaceAll(String, String)
    5751     * @see java.util.regex.Pattern
    5752     * @see java.util.regex.Pattern#DOTALL
    5753     * @since 3.5
    5754     * @deprecated Moved to RegExUtils.
    5755     */
    5756    @Deprecated
    5757    public static String removeAll(final String text, final String regex) {
    5758        return RegExUtils.removeAll(text, regex);
    5759    }
    5760
    5761    /**
    5762     * Removes a substring only if it is at the end of a source string, otherwise returns the source string.
    5763     *
    5764     * <p>
    5765     * 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
    5766     * the source string.
    5767     * </p>
    5768     *
    5769     * <pre>
    5770     * StringUtils.removeEnd(null, *)      = null
    5771     * StringUtils.removeEnd("", *)        = ""
    5772     * StringUtils.removeEnd(*, null)      = *
    5773     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    5774     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    5775     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    5776     * StringUtils.removeEnd("abc", "")    = "abc"
    5777     * </pre>
    5778     *
    5779     * @param str    the source String to search, may be null.
    5780     * @param remove the String to search for and remove, may be null.
    5781     * @return the substring with the string removed if found, {@code null} if null String input.
    5782     * @since 2.1
    5783     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}
    5784     */
    5785    @Deprecated
    5786    public static String removeEnd(final String str, final String remove) {
    5787        return Strings.CS.removeEnd(str, remove);
    5788    }
    5789
    5790    /**
    5791     * Case-insensitive removal of a substring if it is at the end of a source string, otherwise returns the source string.
    5792     *
    5793     * <p>
    5794     * 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
    5795     * the source string.
    5796     * </p>
    5797     *
    5798     * <pre>
    5799     * StringUtils.removeEndIgnoreCase(null, *)      = null
    5800     * StringUtils.removeEndIgnoreCase("", *)        = ""
    5801     * StringUtils.removeEndIgnoreCase(*, null)      = *
    5802     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    5803     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    5804     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    5805     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    5806     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    5807     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    5808     * </pre>
    5809     *
    5810     * @param str    the source String to search, may be null.
    5811     * @param remove the String to search for (case-insensitive) and remove, may be null.
    5812     * @return the substring with the string removed if found, {@code null} if null String input.
    5813     * @since 2.4
    5814     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}
    5815     */
    5816    @Deprecated
    5817    public static String removeEndIgnoreCase(final String str, final String remove) {
    5818        return Strings.CI.removeEnd(str, remove);
    5819    }
    5820
    5821    /**
    5822     * Removes the first substring of the text string that matches the given regular expression.
    5823     *
    5824     * This method is a {@code null} safe equivalent to:
    5825     * <ul>
    5826     * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
    5827     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
    5828     * </ul>
    5829     *
    5830     * <p>
    5831     * A {@code null} reference passed to this method is a no-op.
    5832     * </p>
    5833     *
    5834     * <p>
    5835     * The {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as
    5836     * single-line mode in Perl.
    5837     * </p>
    5838     *
    5839     * <pre>{@code
    5840     * StringUtils.removeFirst(null, *)      = null
    5841     * StringUtils.removeFirst("any", (String) null)  = "any"
    5842     * StringUtils.removeFirst("any", "")    = "any"
    5843     * StringUtils.removeFirst("any", ".*")  = ""
    5844     * StringUtils.removeFirst("any", ".+")  = ""
    5845     * StringUtils.removeFirst("abc", ".?")  = "bc"
    5846     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
    5847     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
    5848     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
    5849     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
    5850     * }</pre>
    5851     *
    5852     * @param text  text to remove from, may be null.
    5853     * @param regex the regular expression to which this string is to be matched.
    5854     * @return the text with the first replacement processed, {@code null} if null String input.
    5855     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
    5856     * @see #replaceFirst(String, String, String)
    5857     * @see String#replaceFirst(String, String)
    5858     * @see java.util.regex.Pattern
    5859     * @see java.util.regex.Pattern#DOTALL
    5860     * @since 3.5
    5861     * @deprecated Moved to RegExUtils.
    5862     */
    5863    @Deprecated
    5864    public static String removeFirst(final String text, final String regex) {
    5865        return replaceFirst(text, regex, EMPTY);
    5866    }
    5867
    5868    /**
    5869     * Case-insensitive removal of all occurrences of a substring from within the source string.
    5870     *
    5871     * <p>
    5872     * 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
    5873     * the source string. An empty ("") remove string will return the source string.
    5874     * </p>
    5875     *
    5876     * <pre>
    5877     * StringUtils.removeIgnoreCase(null, *)        = null
    5878     * StringUtils.removeIgnoreCase("", *)          = ""
    5879     * StringUtils.removeIgnoreCase(*, null)        = *
    5880     * StringUtils.removeIgnoreCase(*, "")          = *
    5881     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
    5882     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
    5883     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
    5884     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
    5885     * </pre>
    5886     *
    5887     * @param str    the source String to search, may be null.
    5888     * @param remove the String to search for (case-insensitive) and remove, may be null.
    5889     * @return the substring with the string removed if found, {@code null} if null String input.
    5890     * @since 3.5
    5891     * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}
    5892     */
    5893    @Deprecated
    5894    public static String removeIgnoreCase(final String str, final String remove) {
    5895        return Strings.CI.remove(str, remove);
    5896    }
    5897
    5898    /**
    5899     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
    5900     *
    5901     * This call is a {@code null} safe equivalent to:
    5902     * <ul>
    5903     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
    5904     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
    5905     * </ul>
    5906     *
    5907     * <p>
    5908     * A {@code null} reference passed to this method is a no-op.
    5909     * </p>
    5910     *
    5911     * <pre>{@code
    5912     * StringUtils.removePattern(null, *)       = null
    5913     * StringUtils.removePattern("any", (String) null)   = "any"
    5914     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
    5915     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
    5916     * }</pre>
    5917     *
    5918     * @param source the source string.
    5919     * @param regex  the regular expression to which this string is to be matched.
    5920     * @return The resulting {@link String}.
    5921     * @see #replacePattern(String, String, String)
    5922     * @see String#replaceAll(String, String)
    5923     * @see Pattern#DOTALL
    5924     * @since 3.2
    5925     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    5926     * @deprecated Moved to RegExUtils.
    5927     */
    5928    @Deprecated
    5929    public static String removePattern(final String source, final String regex) {
    5930        return RegExUtils.removePattern(source, regex);
    5931    }
    5932
    5933    /**
    5934     * Removes a char only if it is at the beginning of a source string, otherwise returns the source string.
    5935     *
    5936     * <p>
    5937     * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search char will return
    5938     * the source string.
    5939     * </p>
    5940     *
    5941     * <pre>
    5942     * StringUtils.removeStart(null, *)      = null
    5943     * StringUtils.removeStart("", *)        = ""
    5944     * StringUtils.removeStart(*, null)      = *
    5945     * StringUtils.removeStart("/path", '/') = "path"
    5946     * StringUtils.removeStart("path", '/')  = "path"
    5947     * StringUtils.removeStart("path", 0)    = "path"
    5948     * </pre>
    5949     *
    5950     * @param str    the source String to search, may be null.
    5951     * @param remove the char to search for and remove.
    5952     * @return the substring with the char removed if found, {@code null} if null String input.
    5953     * @since 3.13.0
    5954     */
    5955    public static String removeStart(final String str, final char remove) {
    5956        if (isEmpty(str)) {
    5957            return str;
    5958        }
    5959        return str.charAt(0) == remove ? str.substring(1) : str;
    5960    }
    5961
    5962    /**
    5963     * Removes a substring only if it is at the beginning of a source string, otherwise returns the source string.
    5964     *
    5965     * <p>
    5966     * 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
    5967     * the source string.
    5968     * </p>
    5969     *
    5970     * <pre>
    5971     * StringUtils.removeStart(null, *)                    = null
    5972     * StringUtils.removeStart("", *)                      = ""
    5973     * StringUtils.removeStart(*, null)                    = *
    5974     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    5975     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    5976     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    5977     * StringUtils.removeStart("abc", "")                  = "abc"
    5978     * </pre>
    5979     *
    5980     * @param str    the source String to search, may be null.
    5981     * @param remove the String to search for and remove, may be null.
    5982     * @return the substring with the string removed if found, {@code null} if null String input.
    5983     * @since 2.1
    5984     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CS.removeStart(String, CharSequence)}
    5985     */
    5986    @Deprecated
    5987    public static String removeStart(final String str, final String remove) {
    5988        return Strings.CS.removeStart(str, remove);
    5989    }
    5990
    5991    /**
    5992     * Case-insensitive removal of a substring if it is at the beginning of a source string, otherwise returns the source string.
    5993     *
    5994     * <p>
    5995     * 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
    5996     * the source string.
    5997     * </p>
    5998     *
    5999     * <pre>
    6000     * StringUtils.removeStartIgnoreCase(null, *)                    = null
    6001     * StringUtils.removeStartIgnoreCase("", *)                      = ""
    6002     * StringUtils.removeStartIgnoreCase(*, null)                    = *
    6003     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
    6004     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
    6005     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
    6006     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    6007     * StringUtils.removeStartIgnoreCase("abc", "")                  = "abc"
    6008     * </pre>
    6009     *
    6010     * @param str    the source String to search, may be null.
    6011     * @param remove the String to search for (case-insensitive) and remove, may be null.
    6012     * @return the substring with the string removed if found, {@code null} if null String input.
    6013     * @since 2.4
    6014     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}
    6015     */
    6016    @Deprecated
    6017    public static String removeStartIgnoreCase(final String str, final String remove) {
    6018        return Strings.CI.removeStart(str, remove);
    6019    }
    6020
    6021    /**
    6022     * Returns padding using the specified delimiter repeated to a given length.
    6023     *
    6024     * <pre>
    6025     * StringUtils.repeat('e', 0)  = ""
    6026     * StringUtils.repeat('e', 3)  = "eee"
    6027     * StringUtils.repeat('e', -2) = ""
    6028     * </pre>
    6029     *
    6030     * <p>
    6031     * Note: this method does not support padding with <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    6032     * as they require a pair of {@code char}s to be represented. If you are needing to support full I18N of your applications consider using
    6033     * {@link #repeat(String, int)} instead.
    6034     * </p>
    6035     *
    6036     * @param repeat character to repeat.
    6037     * @param count  number of times to repeat char, negative treated as zero.
    6038     * @return String with repeated character.
    6039     * @see #repeat(String, int)
    6040     */
    6041    public static String repeat(final char repeat, final int count) {
    6042        if (count <= 0) {
    6043            return EMPTY;
    6044        }
    6045        return new String(ArrayFill.fill(new char[count], repeat));
    6046    }
    6047
    6048    /**
    6049     * Repeats a String {@code repeat} times to form a new String.
    6050     *
    6051     * <pre>
    6052     * StringUtils.repeat(null, 2) = null
    6053     * StringUtils.repeat("", 0)   = ""
    6054     * StringUtils.repeat("", 2)   = ""
    6055     * StringUtils.repeat("a", 3)  = "aaa"
    6056     * StringUtils.repeat("ab", 2) = "abab"
    6057     * StringUtils.repeat("a", -2) = ""
    6058     * </pre>
    6059     *
    6060     * @param repeat the String to repeat, may be null.
    6061     * @param count  number of times to repeat str, negative treated as zero.
    6062     * @return a new String consisting of the original String repeated, {@code null} if null String input.
    6063     */
    6064    public static String repeat(final String repeat, final int count) {
    6065        // Performance tuned for 2.0 (JDK1.4)
    6066        if (repeat == null) {
    6067            return null;
    6068        }
    6069        if (count <= 0) {
    6070            return EMPTY;
    6071        }
    6072        final int inputLength = repeat.length();
    6073        if (count == 1 || inputLength == 0) {
    6074            return repeat;
    6075        }
    6076        if (inputLength == 1 && count <= PAD_LIMIT) {
    6077            return repeat(repeat.charAt(0), count);
    6078        }
    6079        final int outputLength = inputLength * count;
    6080        switch (inputLength) {
    6081        case 1:
    6082            return repeat(repeat.charAt(0), count);
    6083        case 2:
    6084            final char ch0 = repeat.charAt(0);
    6085            final char ch1 = repeat.charAt(1);
    6086            final char[] output2 = new char[outputLength];
    6087            for (int i = count * 2 - 2; i >= 0; i--, i--) {
    6088                output2[i] = ch0;
    6089                output2[i + 1] = ch1;
    6090            }
    6091            return new String(output2);
    6092        default:
    6093            final StringBuilder buf = new StringBuilder(outputLength);
    6094            for (int i = 0; i < count; i++) {
    6095                buf.append(repeat);
    6096            }
    6097            return buf.toString();
    6098        }
    6099    }
    6100
    6101    /**
    6102     * Repeats a String {@code repeat} times to form a new String, with a String separator injected each time.
    6103     *
    6104     * <pre>
    6105     * StringUtils.repeat(null, null, 2) = null
    6106     * StringUtils.repeat(null, "x", 2)  = null
    6107     * StringUtils.repeat("", null, 0)   = ""
    6108     * StringUtils.repeat("", "", 2)     = ""
    6109     * StringUtils.repeat("", "x", 3)    = "xx"
    6110     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    6111     * </pre>
    6112     *
    6113     * @param repeat    the String to repeat, may be null.
    6114     * @param separator the String to inject, may be null.
    6115     * @param count     number of times to repeat str, negative treated as zero.
    6116     * @return a new String consisting of the original String repeated, {@code null} if null String input.
    6117     * @since 2.5
    6118     */
    6119    public static String repeat(final String repeat, final String separator, final int count) {
    6120        if (repeat == null || separator == null) {
    6121            return repeat(repeat, count);
    6122        }
    6123        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    6124        final String result = repeat(repeat + separator, count);
    6125        return Strings.CS.removeEnd(result, separator);
    6126    }
    6127
    6128    /**
    6129     * Replaces all occurrences of a String within another String.
    6130     *
    6131     * <p>
    6132     * A {@code null} reference passed to this method is a no-op.
    6133     * </p>
    6134     *
    6135     * <pre>
    6136     * StringUtils.replace(null, *, *)        = null
    6137     * StringUtils.replace("", *, *)          = ""
    6138     * StringUtils.replace("any", null, *)    = "any"
    6139     * StringUtils.replace("any", *, null)    = "any"
    6140     * StringUtils.replace("any", "", *)      = "any"
    6141     * StringUtils.replace("aba", "a", null)  = "aba"
    6142     * StringUtils.replace("aba", "a", "")    = "b"
    6143     * StringUtils.replace("aba", "a", "z")   = "zbz"
    6144     * </pre>
    6145     *
    6146     * @param text         text to search and replace in, may be null.
    6147     * @param searchString the String to search for, may be null.
    6148     * @param replacement  the String to replace it with, may be null.
    6149     * @return the text with any replacements processed, {@code null} if null String input.
    6150     * @see #replace(String text, String searchString, String replacement, int max)
    6151     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}
    6152     */
    6153    @Deprecated
    6154    public static String replace(final String text, final String searchString, final String replacement) {
    6155        return Strings.CS.replace(text, searchString, replacement);
    6156    }
    6157
    6158    /**
    6159     * Replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
    6160     *
    6161     * <p>
    6162     * A {@code null} reference passed to this method is a no-op.
    6163     * </p>
    6164     *
    6165     * <pre>
    6166     * StringUtils.replace(null, *, *, *)         = null
    6167     * StringUtils.replace("", *, *, *)           = ""
    6168     * StringUtils.replace("any", null, *, *)     = "any"
    6169     * StringUtils.replace("any", *, null, *)     = "any"
    6170     * StringUtils.replace("any", "", *, *)       = "any"
    6171     * StringUtils.replace("any", *, *, 0)        = "any"
    6172     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    6173     * StringUtils.replace("abaa", "a", "", -1)   = "b"
    6174     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    6175     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    6176     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    6177     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    6178     * </pre>
    6179     *
    6180     * @param text         text to search and replace in, may be null.
    6181     * @param searchString the String to search for, may be null.
    6182     * @param replacement  the String to replace it with, may be null.
    6183     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
    6184     * @return the text with any replacements processed, {@code null} if null String input.
    6185     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}
    6186     */
    6187    @Deprecated
    6188    public static String replace(final String text, final String searchString, final String replacement, final int max) {
    6189        return Strings.CS.replace(text, searchString, replacement, max);
    6190    }
    6191
    6192    /**
    6193     * Replaces each substring of the text String that matches the given regular expression with the given replacement.
    6194     *
    6195     * This method is a {@code null} safe equivalent to:
    6196     * <ul>
    6197     * <li>{@code text.replaceAll(regex, replacement)}</li>
    6198     * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
    6199     * </ul>
    6200     *
    6201     * <p>
    6202     * A {@code null} reference passed to this method is a no-op.
    6203     * </p>
    6204     *
    6205     * <p>
    6206     * Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL
    6207     * option prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
    6208     * </p>
    6209     *
    6210     * <pre>{@code
    6211     * StringUtils.replaceAll(null, *, *)                                         = null
    6212     * StringUtils.replaceAll("any", (String) null, *)                            = "any"
    6213     * StringUtils.replaceAll("any", *, null)                                     = "any"
    6214     * StringUtils.replaceAll("", "", "zzz")                                      = "zzz"
    6215     * StringUtils.replaceAll("", ".*", "zzz")                                    = "zzz"
    6216     * StringUtils.replaceAll("", ".+", "zzz")                                    = ""
    6217     * StringUtils.replaceAll("abc", "", "ZZ")                                    = "ZZaZZbZZcZZ"
    6218     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")                          = "z\nz"
    6219     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")                      = "z"
    6220     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")                          = "ABC___123"
    6221     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
    6222     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
    6223     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6224     * }</pre>
    6225     *
    6226     * @param text        text to search and replace in, may be null.
    6227     * @param regex       the regular expression to which this string is to be matched.
    6228     * @param replacement the string to be substituted for each match.
    6229     * @return the text with any replacements processed, {@code null} if null String input.
    6230     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
    6231     * @see #replacePattern(String, String, String)
    6232     * @see String#replaceAll(String, String)
    6233     * @see java.util.regex.Pattern
    6234     * @see java.util.regex.Pattern#DOTALL
    6235     * @since 3.5
    6236     * @deprecated Moved to RegExUtils.
    6237     */
    6238    @Deprecated
    6239    public static String replaceAll(final String text, final String regex, final String replacement) {
    6240        return RegExUtils.replaceAll(text, regex, replacement);
    6241    }
    6242
    6243    /**
    6244     * Replaces all occurrences of a character in a String with another. This is a null-safe version of {@link String#replace(char, char)}.
    6245     *
    6246     * <p>
    6247     * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string.
    6248     * </p>
    6249     *
    6250     * <pre>
    6251     * StringUtils.replaceChars(null, *, *)        = null
    6252     * StringUtils.replaceChars("", *, *)          = ""
    6253     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    6254     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    6255     * </pre>
    6256     *
    6257     * @param str         String to replace characters in, may be null.
    6258     * @param searchChar  the character to search for, may be null.
    6259     * @param replaceChar the character to replace, may be null.
    6260     * @return modified String, {@code null} if null string input.
    6261     * @since 2.0
    6262     */
    6263    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
    6264        if (str == null) {
    6265            return null;
    6266        }
    6267        return str.replace(searchChar, replaceChar);
    6268    }
    6269
    6270    /**
    6271     * Replaces multiple characters in a String in one go. This method can also be used to delete characters.
    6272     *
    6273     * <p>
    6274     * For example:<br>
    6275     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.
    6276     * </p>
    6277     *
    6278     * <p>
    6279     * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string. A null or empty set of search characters returns
    6280     * the input string.
    6281     * </p>
    6282     *
    6283     * <p>
    6284     * The length of the search characters should normally equal the length of the replace characters. If the search characters is longer, then the extra search
    6285     * characters are deleted. If the search characters is shorter, then the extra replace characters are ignored.
    6286     * </p>
    6287     *
    6288     * <pre>
    6289     * StringUtils.replaceChars(null, *, *)           = null
    6290     * StringUtils.replaceChars("", *, *)             = ""
    6291     * StringUtils.replaceChars("abc", null, *)       = "abc"
    6292     * StringUtils.replaceChars("abc", "", *)         = "abc"
    6293     * StringUtils.replaceChars("abc", "b", null)     = "ac"
    6294     * StringUtils.replaceChars("abc", "b", "")       = "ac"
    6295     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    6296     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    6297     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    6298     * </pre>
    6299     *
    6300     * @param str          String to replace characters in, may be null.
    6301     * @param searchChars  a set of characters to search for, may be null.
    6302     * @param replaceChars a set of characters to replace, may be null.
    6303     * @return modified String, {@code null} if null string input.
    6304     * @since 2.0
    6305     */
    6306    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
    6307        if (isEmpty(str) || isEmpty(searchChars)) {
    6308            return str;
    6309        }
    6310        replaceChars = ObjectUtils.toString(replaceChars);
    6311        boolean modified = false;
    6312        final int replaceCharsLength = replaceChars.length();
    6313        final int strLength = str.length();
    6314        final StringBuilder buf = new StringBuilder(strLength);
    6315        for (int i = 0; i < strLength; i++) {
    6316            final char ch = str.charAt(i);
    6317            final int index = searchChars.indexOf(ch);
    6318            if (index >= 0) {
    6319                modified = true;
    6320                if (index < replaceCharsLength) {
    6321                    buf.append(replaceChars.charAt(index));
    6322                }
    6323            } else {
    6324                buf.append(ch);
    6325            }
    6326        }
    6327        if (modified) {
    6328            return buf.toString();
    6329        }
    6330        return str;
    6331    }
    6332
    6333    /**
    6334     * Replaces all occurrences of Strings within another String.
    6335     *
    6336     * <p>
    6337     * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored. This
    6338     * will not repeat. For repeating replaces, call the overloaded method.
    6339     * </p>
    6340     *
    6341     * <pre>
    6342     *  StringUtils.replaceEach(null, *, *)                                                = null
    6343     *  StringUtils.replaceEach("", *, *)                                                  = ""
    6344     *  StringUtils.replaceEach("aba", null, null)                                         = "aba"
    6345     *  StringUtils.replaceEach("aba", new String[0], null)                                = "aba"
    6346     *  StringUtils.replaceEach("aba", null, new String[0])                                = "aba"
    6347     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)                            = "aba"
    6348     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})                = "b"
    6349     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})              = "aba"
    6350     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    6351     *  (example of how it does not repeat)
    6352     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    6353     * </pre>
    6354     *
    6355     * @param text            text to search and replace in, no-op if null.
    6356     * @param searchList      the Strings to search for, no-op if null.
    6357     * @param replacementList the Strings to replace them with, no-op if null.
    6358     * @return the text with any replacements processed, {@code null} if null String input.
    6359     * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
    6360     * @since 2.4
    6361     */
    6362    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
    6363        return replaceEach(text, searchList, replacementList, false, 0);
    6364    }
    6365
    6366    /**
    6367     * Replace all occurrences of Strings within another String. This is a private recursive helper method for
    6368     * {@link #replaceEachRepeatedly(String, String[], String[])} and {@link #replaceEach(String, String[], String[])}
    6369     *
    6370     * <p>
    6371     * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored.
    6372     * </p>
    6373     *
    6374     * <pre>
    6375     *  StringUtils.replaceEach(null, *, *, *, *)                                                     = null
    6376     *  StringUtils.replaceEach("", *, *, *, *)                                                       = ""
    6377     *  StringUtils.replaceEach("aba", null, null, *, *)                                              = "aba"
    6378     *  StringUtils.replaceEach("aba", new String[0], null, *, *)                                     = "aba"
    6379     *  StringUtils.replaceEach("aba", null, new String[0], *, *)                                     = "aba"
    6380     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *)                                 = "aba"
    6381     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0)                   = "b"
    6382     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0)                 = "aba"
    6383     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0)     = "wcte"
    6384     *  (example of how it repeats)
    6385     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
    6386     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2)  = "tcte"
    6387     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *)      = IllegalStateException
    6388     * </pre>
    6389     *
    6390     * @param text            text to search and replace in, no-op if null.
    6391     * @param searchList      the Strings to search for, no-op if null.
    6392     * @param replacementList the Strings to replace them with, no-op if null.
    6393     * @param repeat          if true, then replace repeatedly until there are no more possible replacements or timeToLive < 0.
    6394     * @param timeToLive      if less than 0 then there is a circular reference and endless loop.
    6395     * @return the text with any replacements processed, {@code null} if null String input.
    6396     * @throws IllegalStateException    if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
    6397     * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
    6398     * @since 2.4
    6399     */
    6400    private static String replaceEach(
    6401            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
    6402
    6403        // mchyzer Performance note: This creates very few new objects (one major goal)
    6404        // let me know if there are performance requests, we can create a harness to measure
    6405        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
    6406            return text;
    6407        }
    6408
    6409        // if recursing, this shouldn't be less than 0
    6410        if (timeToLive < 0) {
    6411            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
    6412                "output of one loop is the input of another");
    6413        }
    6414
    6415        final int searchLength = searchList.length;
    6416        final int replacementLength = replacementList.length;
    6417
    6418        // make sure lengths are ok, these need to be equal
    6419        if (searchLength != replacementLength) {
    6420            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    6421                + searchLength
    6422                + " vs "
    6423                + replacementLength);
    6424        }
    6425
    6426        // keep track of which still have matches
    6427        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    6428
    6429        // index on index that the match was found
    6430        int textIndex = -1;
    6431        int replaceIndex = -1;
    6432        int tempIndex;
    6433
    6434        // index of replace array that will replace the search string found
    6435        // NOTE: logic duplicated below START
    6436        for (int i = 0; i < searchLength; i++) {
    6437            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6438                continue;
    6439            }
    6440            tempIndex = text.indexOf(searchList[i]);
    6441
    6442            // see if we need to keep searching for this
    6443            if (tempIndex == -1) {
    6444                noMoreMatchesForReplIndex[i] = true;
    6445            } else if (textIndex == -1 || tempIndex < textIndex) {
    6446                textIndex = tempIndex;
    6447                replaceIndex = i;
    6448            }
    6449        }
    6450        // NOTE: logic mostly below END
    6451
    6452        // no search strings found, we are done
    6453        if (textIndex == -1) {
    6454            return text;
    6455        }
    6456
    6457        int start = 0;
    6458
    6459        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
    6460        int increase = 0;
    6461
    6462        // count the replacement text elements that are larger than their corresponding text being replaced
    6463        for (int i = 0; i < searchList.length; i++) {
    6464            if (searchList[i] == null || replacementList[i] == null) {
    6465                continue;
    6466            }
    6467            final int greater = replacementList[i].length() - searchList[i].length();
    6468            if (greater > 0) {
    6469                increase += 3 * greater; // assume 3 matches
    6470            }
    6471        }
    6472        // have upper-bound at 20% increase, then let Java take over
    6473        increase = Math.min(increase, text.length() / 5);
    6474
    6475        final StringBuilder buf = new StringBuilder(text.length() + increase);
    6476
    6477        while (textIndex != -1) {
    6478
    6479            for (int i = start; i < textIndex; i++) {
    6480                buf.append(text.charAt(i));
    6481            }
    6482            buf.append(replacementList[replaceIndex]);
    6483
    6484            start = textIndex + searchList[replaceIndex].length();
    6485
    6486            textIndex = -1;
    6487            replaceIndex = -1;
    6488            // find the next earliest match
    6489            // NOTE: logic mostly duplicated above START
    6490            for (int i = 0; i < searchLength; i++) {
    6491                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6492                    continue;
    6493                }
    6494                tempIndex = text.indexOf(searchList[i], start);
    6495
    6496                // see if we need to keep searching for this
    6497                if (tempIndex == -1) {
    6498                    noMoreMatchesForReplIndex[i] = true;
    6499                } else if (textIndex == -1 || tempIndex < textIndex) {
    6500                    textIndex = tempIndex;
    6501                    replaceIndex = i;
    6502                }
    6503            }
    6504            // NOTE: logic duplicated above END
    6505
    6506        }
    6507        final int textLength = text.length();
    6508        for (int i = start; i < textLength; i++) {
    6509            buf.append(text.charAt(i));
    6510        }
    6511        final String result = buf.toString();
    6512        if (!repeat) {
    6513            return result;
    6514        }
    6515
    6516        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    6517    }
    6518
    6519    /**
    6520     * Replaces all occurrences of Strings within another String.
    6521     *
    6522     * <p>
    6523     * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored.
    6524     * </p>
    6525     *
    6526     * <pre>
    6527     *  StringUtils.replaceEachRepeatedly(null, *, *)                                                = null
    6528     *  StringUtils.replaceEachRepeatedly("", *, *)                                                  = ""
    6529     *  StringUtils.replaceEachRepeatedly("aba", null, null)                                         = "aba"
    6530     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null)                                = "aba"
    6531     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0])                                = "aba"
    6532     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null)                            = "aba"
    6533     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""})                = "b"
    6534     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"})              = "aba"
    6535     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    6536     *  (example of how it repeats)
    6537     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "tcte"
    6538     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
    6539     * </pre>
    6540     *
    6541     * @param text            text to search and replace in, no-op if null.
    6542     * @param searchList      the Strings to search for, no-op if null.
    6543     * @param replacementList the Strings to replace them with, no-op if null.
    6544     * @return the text with any replacements processed, {@code null} if null String input.
    6545     * @throws IllegalStateException    if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
    6546     * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
    6547     * @since 2.4
    6548     */
    6549    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
    6550        final int timeToLive = Math.max(ArrayUtils.getLength(searchList), DEFAULT_TTL);
    6551        return replaceEach(text, searchList, replacementList, true, timeToLive);
    6552    }
    6553
    6554    /**
    6555     * Replaces the first substring of the text string that matches the given regular expression with the given replacement.
    6556     *
    6557     * This method is a {@code null} safe equivalent to:
    6558     * <ul>
    6559     * <li>{@code text.replaceFirst(regex, replacement)}</li>
    6560     * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
    6561     * </ul>
    6562     *
    6563     * <p>
    6564     * A {@code null} reference passed to this method is a no-op.
    6565     * </p>
    6566     *
    6567     * <p>
    6568     * The {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as
    6569     * single-line mode in Perl.
    6570     * </p>
    6571     *
    6572     * <pre>{@code
    6573     * StringUtils.replaceFirst(null, *, *)       = null
    6574     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
    6575     * StringUtils.replaceFirst("any", *, null)   = "any"
    6576     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
    6577     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
    6578     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
    6579     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
    6580     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
    6581     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
    6582     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
    6583     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
    6584     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
    6585     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
    6586     * }</pre>
    6587     *
    6588     * @param text        text to search and replace in, may be null.
    6589     * @param regex       the regular expression to which this string is to be matched.
    6590     * @param replacement the string to be substituted for the first match.
    6591     * @return the text with the first replacement processed, {@code null} if null String input.
    6592     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
    6593     * @see String#replaceFirst(String, String)
    6594     * @see java.util.regex.Pattern
    6595     * @see java.util.regex.Pattern#DOTALL
    6596     * @since 3.5
    6597     * @deprecated Moved to RegExUtils.
    6598     */
    6599    @Deprecated
    6600    public static String replaceFirst(final String text, final String regex, final String replacement) {
    6601        return RegExUtils.replaceFirst(text, regex, replacement);
    6602    }
    6603
    6604    /**
    6605     * Case insensitively replaces all occurrences of a String within another String.
    6606     *
    6607     * <p>
    6608     * A {@code null} reference passed to this method is a no-op.
    6609     * </p>
    6610     *
    6611     * <pre>
    6612     * StringUtils.replaceIgnoreCase(null, *, *)        = null
    6613     * StringUtils.replaceIgnoreCase("", *, *)          = ""
    6614     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
    6615     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
    6616     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
    6617     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
    6618     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
    6619     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
    6620     * </pre>
    6621     *
    6622     * @param text         text to search and replace in, may be null.
    6623     * @param searchString the String to search for (case-insensitive), may be null.
    6624     * @param replacement  the String to replace it with, may be null.
    6625     * @return the text with any replacements processed, {@code null} if null String input.
    6626     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6627     * @since 3.5
    6628     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}
    6629     */
    6630    @Deprecated
    6631    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
    6632        return Strings.CI.replace(text, searchString, replacement);
    6633    }
    6634
    6635    /**
    6636     * Case insensitively replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
    6637     *
    6638     * <p>
    6639     * A {@code null} reference passed to this method is a no-op.
    6640     * </p>
    6641     *
    6642     * <pre>
    6643     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
    6644     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
    6645     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
    6646     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
    6647     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
    6648     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
    6649     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
    6650     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
    6651     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
    6652     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
    6653     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
    6654     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
    6655     * </pre>
    6656     *
    6657     * @param text         text to search and replace in, may be null.
    6658     * @param searchString the String to search for (case-insensitive), may be null.
    6659     * @param replacement  the String to replace it with, may be null.
    6660     * @param max          maximum number of values to replace, or {@code -1} if no maximum.
    6661     * @return the text with any replacements processed, {@code null} if null String input.
    6662     * @since 3.5
    6663     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}
    6664     */
    6665    @Deprecated
    6666    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
    6667        return Strings.CI.replace(text, searchString, replacement, max);
    6668    }
    6669
    6670    /**
    6671     * Replaces a String with another String inside a larger String, once.
    6672     *
    6673     * <p>
    6674     * A {@code null} reference passed to this method is a no-op.
    6675     * </p>
    6676     *
    6677     * <pre>
    6678     * StringUtils.replaceOnce(null, *, *)        = null
    6679     * StringUtils.replaceOnce("", *, *)          = ""
    6680     * StringUtils.replaceOnce("any", null, *)    = "any"
    6681     * StringUtils.replaceOnce("any", *, null)    = "any"
    6682     * StringUtils.replaceOnce("any", "", *)      = "any"
    6683     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    6684     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    6685     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    6686     * </pre>
    6687     *
    6688     * @param text         text to search and replace in, may be null.
    6689     * @param searchString the String to search for, may be null.
    6690     * @param replacement  the String to replace with, may be null.
    6691     * @return the text with any replacements processed, {@code null} if null String input.
    6692     * @see #replace(String text, String searchString, String replacement, int max)
    6693     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}
    6694     */
    6695    @Deprecated
    6696    public static String replaceOnce(final String text, final String searchString, final String replacement) {
    6697        return Strings.CS.replaceOnce(text, searchString, replacement);
    6698    }
    6699
    6700    /**
    6701     * Case insensitively replaces a String with another String inside a larger String, once.
    6702     *
    6703     * <p>
    6704     * A {@code null} reference passed to this method is a no-op.
    6705     * </p>
    6706     *
    6707     * <pre>
    6708     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
    6709     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
    6710     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
    6711     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
    6712     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
    6713     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
    6714     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
    6715     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
    6716     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
    6717     * </pre>
    6718     *
    6719     * @param text         text to search and replace in, may be null.
    6720     * @param searchString the String to search for (case-insensitive), may be null.
    6721     * @param replacement  the String to replace with, may be null.
    6722     * @return the text with any replacements processed, {@code null} if null String input.
    6723     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6724     * @since 3.5
    6725     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}
    6726     */
    6727    @Deprecated
    6728    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
    6729        return Strings.CI.replaceOnce(text, searchString, replacement);
    6730    }
    6731
    6732    /**
    6733     * Replaces each substring of the source String that matches the given regular expression with the given replacement using the {@link Pattern#DOTALL}
    6734     * option. DOTALL is also known as single-line mode in Perl.
    6735     *
    6736     * This call is a {@code null} safe equivalent to:
    6737     * <ul>
    6738     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
    6739     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
    6740     * </ul>
    6741     *
    6742     * <p>
    6743     * A {@code null} reference passed to this method is a no-op.
    6744     * </p>
    6745     *
    6746     * <pre>{@code
    6747     * StringUtils.replacePattern(null, *, *)                                         = null
    6748     * StringUtils.replacePattern("any", (String) null, *)                            = "any"
    6749     * StringUtils.replacePattern("any", *, null)                                     = "any"
    6750     * StringUtils.replacePattern("", "", "zzz")                                      = "zzz"
    6751     * StringUtils.replacePattern("", ".*", "zzz")                                    = "zzz"
    6752     * StringUtils.replacePattern("", ".+", "zzz")                                    = ""
    6753     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")                          = "z"
    6754     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")                          = "ABC___123"
    6755     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
    6756     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
    6757     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6758     * }</pre>
    6759     *
    6760     * @param source      the source string.
    6761     * @param regex       the regular expression to which this string is to be matched.
    6762     * @param replacement the string to be substituted for each match.
    6763     * @return The resulting {@link String}.
    6764     * @see #replaceAll(String, String, String)
    6765     * @see String#replaceAll(String, String)
    6766     * @see Pattern#DOTALL
    6767     * @since 3.2
    6768     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    6769     * @deprecated Moved to RegExUtils.
    6770     */
    6771    @Deprecated
    6772    public static String replacePattern(final String source, final String regex, final String replacement) {
    6773        return RegExUtils.replacePattern(source, regex, replacement);
    6774    }
    6775
    6776    /**
    6777     * Reverses a String as per {@link StringBuilder#reverse()}.
    6778     *
    6779     * <p>
    6780     * A {@code null} String returns {@code null}.
    6781     * </p>
    6782     *
    6783     * <pre>
    6784     * StringUtils.reverse(null)  = null
    6785     * StringUtils.reverse("")    = ""
    6786     * StringUtils.reverse("bat") = "tab"
    6787     * </pre>
    6788     *
    6789     * @param str the String to reverse, may be null.
    6790     * @return the reversed String, {@code null} if null String input.
    6791     */
    6792    public static String reverse(final String str) {
    6793        if (str == null) {
    6794            return null;
    6795        }
    6796        return new StringBuilder(str).reverse().toString();
    6797    }
    6798
    6799    /**
    6800     * Reverses a String that is delimited by a specific character.
    6801     *
    6802     * <p>
    6803     * The Strings between the delimiters are not reversed. Thus java.lang.String becomes String.lang.java (if the delimiter is {@code '.'}).
    6804     * </p>
    6805     *
    6806     * <pre>
    6807     * StringUtils.reverseDelimited(null, *)      = null
    6808     * StringUtils.reverseDelimited("", *)        = ""
    6809     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    6810     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    6811     * </pre>
    6812     *
    6813     * @param str           the String to reverse, may be null.
    6814     * @param separatorChar the separator character to use.
    6815     * @return the reversed String, {@code null} if null String input.
    6816     * @since 2.0
    6817     */
    6818    public static String reverseDelimited(final String str, final char separatorChar) {
    6819        final String[] strs = split(str, separatorChar);
    6820        ArrayUtils.reverse(strs);
    6821        return join(strs, separatorChar);
    6822    }
    6823
    6824    /**
    6825     * Gets the rightmost {@code len} characters of a String.
    6826     *
    6827     * <p>
    6828     * If {@code len} characters are not available, or the String is {@code null}, the String will be returned without an an exception. An empty String is
    6829     * returned if len is negative.
    6830     * </p>
    6831     *
    6832     * <pre>
    6833     * StringUtils.right(null, *)    = null
    6834     * StringUtils.right(*, -ve)     = ""
    6835     * StringUtils.right("", *)      = ""
    6836     * StringUtils.right("abc", 0)   = ""
    6837     * StringUtils.right("abc", 2)   = "bc"
    6838     * StringUtils.right("abc", 4)   = "abc"
    6839     * </pre>
    6840     *
    6841     * @param str the String to get the rightmost characters from, may be null.
    6842     * @param len the length of the required String.
    6843     * @return the rightmost characters, {@code null} if null String input.
    6844     */
    6845    public static String right(final String str, final int len) {
    6846        if (str == null) {
    6847            return null;
    6848        }
    6849        if (len < 0) {
    6850            return EMPTY;
    6851        }
    6852        if (str.length() <= len) {
    6853            return str;
    6854        }
    6855        return str.substring(str.length() - len);
    6856    }
    6857
    6858    /**
    6859     * Right pad a String with spaces (' ').
    6860     *
    6861     * <p>
    6862     * The String is padded to the size of {@code size}.
    6863     * </p>
    6864     *
    6865     * <pre>
    6866     * StringUtils.rightPad(null, *)   = null
    6867     * StringUtils.rightPad("", 3)     = "   "
    6868     * StringUtils.rightPad("bat", 3)  = "bat"
    6869     * StringUtils.rightPad("bat", 5)  = "bat  "
    6870     * StringUtils.rightPad("bat", 1)  = "bat"
    6871     * StringUtils.rightPad("bat", -1) = "bat"
    6872     * </pre>
    6873     *
    6874     * @param str  the String to pad out, may be null.
    6875     * @param size the size to pad to.
    6876     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
    6877     */
    6878    public static String rightPad(final String str, final int size) {
    6879        return rightPad(str, size, ' ');
    6880    }
    6881
    6882    /**
    6883     * Right pad a String with a specified character.
    6884     *
    6885     * <p>
    6886     * The String is padded to the size of {@code size}.
    6887     * </p>
    6888     *
    6889     * <pre>
    6890     * StringUtils.rightPad(null, *, *)     = null
    6891     * StringUtils.rightPad("", 3, 'z')     = "zzz"
    6892     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    6893     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    6894     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    6895     * StringUtils.rightPad("bat", -1, 'z') = "bat"
    6896     * </pre>
    6897     *
    6898     * @param str     the String to pad out, may be null.
    6899     * @param size    the size to pad to.
    6900     * @param padChar the character to pad with.
    6901     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
    6902     * @since 2.0
    6903     */
    6904    public static String rightPad(final String str, final int size, final char padChar) {
    6905        if (str == null) {
    6906            return null;
    6907        }
    6908        final int pads = size - str.length();
    6909        if (pads <= 0) {
    6910            return str; // returns original String when possible
    6911        }
    6912        if (pads > PAD_LIMIT) {
    6913            return rightPad(str, size, String.valueOf(padChar));
    6914        }
    6915        return str.concat(repeat(padChar, pads));
    6916    }
    6917
    6918    /**
    6919     * Right pad a String with a specified String.
    6920     *
    6921     * <p>
    6922     * The String is padded to the size of {@code size}.
    6923     * </p>
    6924     *
    6925     * <pre>
    6926     * StringUtils.rightPad(null, *, *)      = null
    6927     * StringUtils.rightPad("", 3, "z")      = "zzz"
    6928     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    6929     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    6930     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    6931     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    6932     * StringUtils.rightPad("bat", -1, "yz") = "bat"
    6933     * StringUtils.rightPad("bat", 5, null)  = "bat  "
    6934     * StringUtils.rightPad("bat", 5, "")    = "bat  "
    6935     * </pre>
    6936     *
    6937     * @param str    the String to pad out, may be null.
    6938     * @param size   the size to pad to.
    6939     * @param padStr the String to pad with, null or empty treated as single space.
    6940     * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
    6941     */
    6942    public static String rightPad(final String str, final int size, String padStr) {
    6943        if (str == null) {
    6944            return null;
    6945        }
    6946        if (isEmpty(padStr)) {
    6947            padStr = SPACE;
    6948        }
    6949        final int padLen = padStr.length();
    6950        final int strLen = str.length();
    6951        final int pads = size - strLen;
    6952        if (pads <= 0) {
    6953            return str; // returns original String when possible
    6954        }
    6955        if (padLen == 1 && pads <= PAD_LIMIT) {
    6956            return rightPad(str, size, padStr.charAt(0));
    6957        }
    6958        if (pads == padLen) {
    6959            return str.concat(padStr);
    6960        }
    6961        if (pads < padLen) {
    6962            return str.concat(padStr.substring(0, pads));
    6963        }
    6964        final char[] padding = new char[pads];
    6965        final char[] padChars = padStr.toCharArray();
    6966        for (int i = 0; i < pads; i++) {
    6967            padding[i] = padChars[i % padLen];
    6968        }
    6969        return str.concat(new String(padding));
    6970    }
    6971
    6972    /**
    6973     * Rotate (circular shift) a String of {@code shift} characters.
    6974     * <ul>
    6975     * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
    6976     * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
    6977     * </ul>
    6978     *
    6979     * <pre>
    6980     * StringUtils.rotate(null, *)        = null
    6981     * StringUtils.rotate("", *)          = ""
    6982     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
    6983     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
    6984     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
    6985     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
    6986     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
    6987     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
    6988     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
    6989     * </pre>
    6990     *
    6991     * @param str   the String to rotate, may be null.
    6992     * @param shift number of time to shift (positive : right shift, negative : left shift).
    6993     * @return the rotated String, or the original String if {@code shift == 0}, or {@code null} if null String input.
    6994     * @since 3.5
    6995     */
    6996    public static String rotate(final String str, final int shift) {
    6997        if (str == null) {
    6998            return null;
    6999        }
    7000        final int strLen = str.length();
    7001        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
    7002            return str;
    7003        }
    7004        final StringBuilder builder = new StringBuilder(strLen);
    7005        final int offset = -(shift % strLen);
    7006        builder.append(substring(str, offset));
    7007        builder.append(substring(str, 0, offset));
    7008        return builder.toString();
    7009    }
    7010
    7011    /**
    7012     * Splits the provided text into an array, using whitespace as the separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
    7013     *
    7014     * <p>
    7015     * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
    7016     * StrTokenizer class.
    7017     * </p>
    7018     *
    7019     * <p>
    7020     * A {@code null} input String returns {@code null}.
    7021     * </p>
    7022     *
    7023     * <pre>
    7024     * StringUtils.split(null)       = null
    7025     * StringUtils.split("")         = []
    7026     * StringUtils.split("abc def")  = ["abc", "def"]
    7027     * StringUtils.split("abc  def") = ["abc", "def"]
    7028     * StringUtils.split(" abc ")    = ["abc"]
    7029     * </pre>
    7030     *
    7031     * @param str the String to parse, may be null.
    7032     * @return an array of parsed Strings, {@code null} if null String input.
    7033     */
    7034    public static String[] split(final String str) {
    7035        return split(str, null, -1);
    7036    }
    7037
    7038    /**
    7039     * Splits the provided text into an array, separator specified. This is an alternative to using StringTokenizer.
    7040     *
    7041     * <p>
    7042     * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
    7043     * StrTokenizer class.
    7044     * </p>
    7045     *
    7046     * <p>
    7047     * A {@code null} input String returns {@code null}.
    7048     * </p>
    7049     *
    7050     * <pre>
    7051     * StringUtils.split(null, *)         = null
    7052     * StringUtils.split("", *)           = []
    7053     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    7054     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    7055     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    7056     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    7057     * </pre>
    7058     *
    7059     * @param str           the String to parse, may be null.
    7060     * @param separatorChar the character used as the delimiter.
    7061     * @return an array of parsed Strings, {@code null} if null String input.
    7062     * @since 2.0
    7063     */
    7064    public static String[] split(final String str, final char separatorChar) {
    7065        return splitWorker(str, separatorChar, false);
    7066    }
    7067
    7068    /**
    7069     * Splits the provided text into an array, separators specified. This is an alternative to using StringTokenizer.
    7070     *
    7071     * <p>
    7072     * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
    7073     * StrTokenizer class.
    7074     * </p>
    7075     *
    7076     * <p>
    7077     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
    7078     * </p>
    7079     *
    7080     * <pre>
    7081     * StringUtils.split(null, *)         = null
    7082     * StringUtils.split("", *)           = []
    7083     * StringUtils.split("abc def", null) = ["abc", "def"]
    7084     * StringUtils.split("abc def", " ")  = ["abc", "def"]
    7085     * StringUtils.split("abc  def", " ") = ["abc", "def"]
    7086     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    7087     * </pre>
    7088     *
    7089     * @param str            the String to parse, may be null.
    7090     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
    7091     * @return an array of parsed Strings, {@code null} if null String input.
    7092     */
    7093    public static String[] split(final String str, final String separatorChars) {
    7094        return splitWorker(str, separatorChars, -1, false);
    7095    }
    7096
    7097    /**
    7098     * Splits the provided text into an array with a maximum length, separators specified.
    7099     *
    7100     * <p>
    7101     * The separator is not included in the returned String array. Adjacent separators are treated as one separator.
    7102     * </p>
    7103     *
    7104     * <p>
    7105     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
    7106     * </p>
    7107     *
    7108     * <p>
    7109     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
    7110     * strings (including separator characters).
    7111     * </p>
    7112     *
    7113     * <pre>
    7114     * StringUtils.split(null, *, *)            = null
    7115     * StringUtils.split("", *, *)              = []
    7116     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
    7117     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
    7118     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7119     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7120     * </pre>
    7121     *
    7122     * @param str            the String to parse, may be null.
    7123     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
    7124     * @param max            the maximum number of elements to include in the array. A zero or negative value implies no limit.
    7125     * @return an array of parsed Strings, {@code null} if null String input.
    7126     */
    7127    public static String[] split(final String str, final String separatorChars, final int max) {
    7128        return splitWorker(str, separatorChars, max, false);
    7129    }
    7130
    7131    /**
    7132     * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
    7133     * as complete tokens.
    7134     *
    7135     * <pre>
    7136     * StringUtils.splitByCharacterType(null)         = null
    7137     * StringUtils.splitByCharacterType("")           = []
    7138     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7139     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7140     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7141     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    7142     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    7143     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    7144     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    7145     * </pre>
    7146     *
    7147     * @param str the String to split, may be {@code null}.
    7148     * @return an array of parsed Strings, {@code null} if null String input.
    7149     * @since 2.4
    7150     */
    7151    public static String[] splitByCharacterType(final String str) {
    7152        return splitByCharacterType(str, false);
    7153    }
    7154
    7155    /**
    7156     * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
    7157     * as complete tokens, with the following exception: if {@code camelCase} is {@code true}, the character of type {@code Character.UPPERCASE_LETTER}, if any,
    7158     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any,
    7159     * {@code Character.UPPERCASE_LETTER} token.
    7160     *
    7161     * @param str       the String to split, may be {@code null}.
    7162     * @param camelCase whether to use so-called "camel-case" for letter types.
    7163     * @return an array of parsed Strings, {@code null} if null String input.
    7164     * @since 2.4
    7165     */
    7166    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
    7167        if (str == null) {
    7168            return null;
    7169        }
    7170        if (str.isEmpty()) {
    7171            return ArrayUtils.EMPTY_STRING_ARRAY;
    7172        }
    7173        final char[] c = str.toCharArray();
    7174        final List<String> list = new ArrayList<>();
    7175        int tokenStart = 0;
    7176        int currentType = Character.getType(c[tokenStart]);
    7177        for (int pos = tokenStart + 1; pos < c.length; pos++) {
    7178            final int type = Character.getType(c[pos]);
    7179            if (type == currentType) {
    7180                continue;
    7181            }
    7182            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    7183                final int newTokenStart = pos - 1;
    7184                if (newTokenStart != tokenStart) {
    7185                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    7186                    tokenStart = newTokenStart;
    7187                }
    7188            } else {
    7189                list.add(new String(c, tokenStart, pos - tokenStart));
    7190                tokenStart = pos;
    7191            }
    7192            currentType = type;
    7193        }
    7194        list.add(new String(c, tokenStart, c.length - tokenStart));
    7195        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7196    }
    7197
    7198    /**
    7199     * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
    7200     * as complete tokens, with the following exception: the character of type {@code Character.UPPERCASE_LETTER}, if any, immediately preceding a token of type
    7201     * {@code Character.LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any, {@code Character.UPPERCASE_LETTER} token.
    7202     *
    7203     * <pre>
    7204     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    7205     * StringUtils.splitByCharacterTypeCamelCase("")           = []
    7206     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7207     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7208     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7209     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    7210     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    7211     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    7212     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    7213     * </pre>
    7214     *
    7215     * @param str the String to split, may be {@code null}.
    7216     * @return an array of parsed Strings, {@code null} if null String input.
    7217     * @since 2.4
    7218     */
    7219    public static String[] splitByCharacterTypeCamelCase(final String str) {
    7220        return splitByCharacterType(str, true);
    7221    }
    7222
    7223    /**
    7224     * Splits the provided text into an array, separator string specified.
    7225     *
    7226     * <p>
    7227     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
    7228     * </p>
    7229     *
    7230     * <p>
    7231     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
    7232     * </p>
    7233     *
    7234     * <pre>
    7235     * StringUtils.splitByWholeSeparator(null, *)               = null
    7236     * StringUtils.splitByWholeSeparator("", *)                 = []
    7237     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    7238     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    7239     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7240     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7241     * </pre>
    7242     *
    7243     * @param str       the String to parse, may be null.
    7244     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
    7245     * @return an array of parsed Strings, {@code null} if null String was input.
    7246     */
    7247    public static String[] splitByWholeSeparator(final String str, final String separator) {
    7248        return splitByWholeSeparatorWorker(str, separator, -1, false);
    7249    }
    7250
    7251    /**
    7252     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
    7253     *
    7254     * <p>
    7255     * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
    7256     * </p>
    7257     *
    7258     * <p>
    7259     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
    7260     * </p>
    7261     *
    7262     * <pre>
    7263     * StringUtils.splitByWholeSeparator(null, *, *)               = null
    7264     * StringUtils.splitByWholeSeparator("", *, *)                 = []
    7265     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7266     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    7267     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7268     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7269     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7270     * </pre>
    7271     *
    7272     * @param str       the String to parse, may be null.
    7273     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
    7274     * @param max       the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
    7275     * @return an array of parsed Strings, {@code null} if null String was input.
    7276     */
    7277    public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
    7278        return splitByWholeSeparatorWorker(str, separator, max, false);
    7279    }
    7280
    7281    /**
    7282     * Splits the provided text into an array, separator string specified.
    7283     *
    7284     * <p>
    7285     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
    7286     * split use the StrTokenizer class.
    7287     * </p>
    7288     *
    7289     * <p>
    7290     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
    7291     * </p>
    7292     *
    7293     * <pre>
    7294     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    7295     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    7296     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    7297     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    7298     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7299     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7300     * </pre>
    7301     *
    7302     * @param str       the String to parse, may be null.
    7303     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
    7304     * @return an array of parsed Strings, {@code null} if null String was input.
    7305     * @since 2.4
    7306     */
    7307    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
    7308        return splitByWholeSeparatorWorker(str, separator, -1, true);
    7309    }
    7310
    7311    /**
    7312     * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
    7313     *
    7314     * <p>
    7315     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
    7316     * split use the StrTokenizer class.
    7317     * </p>
    7318     *
    7319     * <p>
    7320     * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
    7321     * </p>
    7322     *
    7323     * <pre>
    7324     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    7325     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    7326     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7327     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    7328     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7329     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7330     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7331     * </pre>
    7332     *
    7333     * @param str       the String to parse, may be null.
    7334     * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
    7335     * @param max       the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
    7336     * @return an array of parsed Strings, {@code null} if null String was input.
    7337     * @since 2.4
    7338     */
    7339    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
    7340        return splitByWholeSeparatorWorker(str, separator, max, true);
    7341    }
    7342
    7343    /**
    7344     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
    7345     *
    7346     * @param str               the String to parse, may be {@code null}.
    7347     * @param separator         String containing the String to be used as a delimiter, {@code null} splits on whitespace.
    7348     * @param max               the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
    7349     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
    7350     *                          one separator.
    7351     * @return an array of parsed Strings, {@code null} if null String input.
    7352     * @since 2.4
    7353     */
    7354    private static String[] splitByWholeSeparatorWorker(final String str, final String separator, final int max, final boolean preserveAllTokens) {
    7355        if (str == null) {
    7356            return null;
    7357        }
    7358        final int len = str.length();
    7359        if (len == 0) {
    7360            return ArrayUtils.EMPTY_STRING_ARRAY;
    7361        }
    7362        if (separator == null || EMPTY.equals(separator)) {
    7363            // Split on whitespace.
    7364            return splitWorker(str, null, max, preserveAllTokens);
    7365        }
    7366        final int separatorLength = separator.length();
    7367        final ArrayList<String> substrings = new ArrayList<>();
    7368        int numberOfSubstrings = 0;
    7369        int beg = 0;
    7370        int end = 0;
    7371        while (end < len) {
    7372            end = str.indexOf(separator, beg);
    7373            if (end > -1) {
    7374                if (end > beg) {
    7375                    numberOfSubstrings += 1;
    7376                    if (numberOfSubstrings == max) {
    7377                        end = len;
    7378                        substrings.add(str.substring(beg));
    7379                    } else {
    7380                        // The following is OK, because String.substring( beg, end ) excludes
    7381                        // the character at the position 'end'.
    7382                        substrings.add(str.substring(beg, end));
    7383                        // Set the starting point for the next search.
    7384                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    7385                        // which is the right calculation:
    7386                        beg = end + separatorLength;
    7387                    }
    7388                } else {
    7389                    // We found a consecutive occurrence of the separator, so skip it.
    7390                    if (preserveAllTokens) {
    7391                        numberOfSubstrings += 1;
    7392                        if (numberOfSubstrings == max) {
    7393                            end = len;
    7394                            substrings.add(str.substring(beg));
    7395                        } else {
    7396                            substrings.add(EMPTY);
    7397                        }
    7398                    }
    7399                    beg = end + separatorLength;
    7400                }
    7401            } else {
    7402                // String.substring( beg ) goes from 'beg' to the end of the String.
    7403                substrings.add(str.substring(beg));
    7404                end = len;
    7405            }
    7406        }
    7407        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7408    }
    7409
    7410    /**
    7411     * Splits the provided text into an array, using whitespace as the separator, preserving all tokens, including empty tokens created by adjacent separators.
    7412     * This is an alternative to using StringTokenizer. Whitespace is defined by {@link Character#isWhitespace(char)}.
    7413     *
    7414     * <p>
    7415     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
    7416     * split use the StrTokenizer class.
    7417     * </p>
    7418     *
    7419     * <p>
    7420     * A {@code null} input String returns {@code null}.
    7421     * </p>
    7422     *
    7423     * <pre>
    7424     * StringUtils.splitPreserveAllTokens(null)       = null
    7425     * StringUtils.splitPreserveAllTokens("")         = []
    7426     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    7427     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    7428     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    7429     * </pre>
    7430     *
    7431     * @param str the String to parse, may be {@code null}.
    7432     * @return an array of parsed Strings, {@code null} if null String input.
    7433     * @since 2.1
    7434     */
    7435    public static String[] splitPreserveAllTokens(final String str) {
    7436        return splitWorker(str, null, -1, true);
    7437    }
    7438
    7439    /**
    7440     * Splits the provided text into an array, separator specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
    7441     * alternative to using StringTokenizer.
    7442     *
    7443     * <p>
    7444     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
    7445     * split use the StrTokenizer class.
    7446     * </p>
    7447     *
    7448     * <p>
    7449     * A {@code null} input String returns {@code null}.
    7450     * </p>
    7451     *
    7452     * <pre>
    7453     * StringUtils.splitPreserveAllTokens(null, *)         = null
    7454     * StringUtils.splitPreserveAllTokens("", *)           = []
    7455     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    7456     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    7457     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    7458     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    7459     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    7460     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    7461     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
    7462     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
    7463     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
    7464     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
    7465     * </pre>
    7466     *
    7467     * @param str           the String to parse, may be {@code null}.
    7468     * @param separatorChar the character used as the delimiter, {@code null} splits on whitespace.
    7469     * @return an array of parsed Strings, {@code null} if null String input.
    7470     * @since 2.1
    7471     */
    7472    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
    7473        return splitWorker(str, separatorChar, true);
    7474    }
    7475
    7476    /**
    7477     * Splits the provided text into an array, separators specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
    7478     * alternative to using StringTokenizer.
    7479     *
    7480     * <p>
    7481     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
    7482     * split use the StrTokenizer class.
    7483     * </p>
    7484     *
    7485     * <p>
    7486     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
    7487     * </p>
    7488     *
    7489     * <pre>
    7490     * StringUtils.splitPreserveAllTokens(null, *)           = null
    7491     * StringUtils.splitPreserveAllTokens("", *)             = []
    7492     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    7493     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    7494     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
    7495     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    7496     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    7497     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    7498     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
    7499     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
    7500     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
    7501     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
    7502     * </pre>
    7503     *
    7504     * @param str            the String to parse, may be {@code null}.
    7505     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
    7506     * @return an array of parsed Strings, {@code null} if null String input.
    7507     * @since 2.1
    7508     */
    7509    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
    7510        return splitWorker(str, separatorChars, -1, true);
    7511    }
    7512
    7513    /**
    7514     * Splits the provided text into an array with a maximum length, separators specified, preserving all tokens, including empty tokens created by adjacent
    7515     * separators.
    7516     *
    7517     * <p>
    7518     * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. Adjacent separators are
    7519     * treated as one separator.
    7520     * </p>
    7521     *
    7522     * <p>
    7523     * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
    7524     * </p>
    7525     *
    7526     * <p>
    7527     * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
    7528     * strings (including separator characters).
    7529     * </p>
    7530     *
    7531     * <pre>
    7532     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    7533     * StringUtils.splitPreserveAllTokens("", *, *)              = []
    7534     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
    7535     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
    7536     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7537     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7538     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    7539     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    7540     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    7541     * </pre>
    7542     *
    7543     * @param str            the String to parse, may be {@code null}.
    7544     * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
    7545     * @param max            the maximum number of elements to include in the array. A zero or negative value implies no limit.
    7546     * @return an array of parsed Strings, {@code null} if null String input.
    7547     * @since 2.1
    7548     */
    7549    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
    7550        return splitWorker(str, separatorChars, max, true);
    7551    }
    7552
    7553    /**
    7554     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that do not return a maximum array length.
    7555     *
    7556     * @param str               the String to parse, may be {@code null}.
    7557     * @param separatorChar     the separate character.
    7558     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
    7559     *                          one separator.
    7560     * @return an array of parsed Strings, {@code null} if null String input.
    7561     */
    7562    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
    7563        // Performance tuned for 2.0 (JDK1.4)
    7564        if (str == null) {
    7565            return null;
    7566        }
    7567        final int len = str.length();
    7568        if (len == 0) {
    7569            return ArrayUtils.EMPTY_STRING_ARRAY;
    7570        }
    7571        final List<String> list = new ArrayList<>();
    7572        int i = 0;
    7573        int start = 0;
    7574        boolean match = false;
    7575        boolean lastMatch = false;
    7576        while (i < len) {
    7577            if (str.charAt(i) == separatorChar) {
    7578                if (match || preserveAllTokens) {
    7579                    list.add(str.substring(start, i));
    7580                    match = false;
    7581                    lastMatch = true;
    7582                }
    7583                start = ++i;
    7584                continue;
    7585            }
    7586            lastMatch = false;
    7587            match = true;
    7588            i++;
    7589        }
    7590        if (match || preserveAllTokens && lastMatch) {
    7591            list.add(str.substring(start, i));
    7592        }
    7593        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7594    }
    7595
    7596    /**
    7597     * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that return a maximum array length.
    7598     *
    7599     * @param str               the String to parse, may be {@code null}.
    7600     * @param separatorChars    the separate character.
    7601     * @param max               the maximum number of elements to include in the array. A zero or negative value implies no limit.
    7602     * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
    7603     *                          one separator.
    7604     * @return an array of parsed Strings, {@code null} if null String input.
    7605     */
    7606    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
    7607        // Performance tuned for 2.0 (JDK1.4)
    7608        // Direct code is quicker than StringTokenizer.
    7609        // Also, StringTokenizer uses isSpace() not isWhitespace()
    7610        if (str == null) {
    7611            return null;
    7612        }
    7613        final int len = str.length();
    7614        if (len == 0) {
    7615            return ArrayUtils.EMPTY_STRING_ARRAY;
    7616        }
    7617        final List<String> list = new ArrayList<>();
    7618        int sizePlus1 = 1;
    7619        int i = 0;
    7620        int start = 0;
    7621        boolean match = false;
    7622        boolean lastMatch = false;
    7623        if (separatorChars == null) {
    7624            // Null separator means use whitespace
    7625            while (i < len) {
    7626                if (Character.isWhitespace(str.charAt(i))) {
    7627                    if (match || preserveAllTokens) {
    7628                        lastMatch = true;
    7629                        if (sizePlus1++ == max) {
    7630                            i = len;
    7631                            lastMatch = false;
    7632                        }
    7633                        list.add(str.substring(start, i));
    7634                        match = false;
    7635                    }
    7636                    start = ++i;
    7637                    continue;
    7638                }
    7639                lastMatch = false;
    7640                match = true;
    7641                i++;
    7642            }
    7643        } else if (separatorChars.length() == 1) {
    7644            // Optimize 1 character case
    7645            final char sep = separatorChars.charAt(0);
    7646            while (i < len) {
    7647                if (str.charAt(i) == sep) {
    7648                    if (match || preserveAllTokens) {
    7649                        lastMatch = true;
    7650                        if (sizePlus1++ == max) {
    7651                            i = len;
    7652                            lastMatch = false;
    7653                        }
    7654                        list.add(str.substring(start, i));
    7655                        match = false;
    7656                    }
    7657                    start = ++i;
    7658                    continue;
    7659                }
    7660                lastMatch = false;
    7661                match = true;
    7662                i++;
    7663            }
    7664        } else {
    7665            // standard case
    7666            while (i < len) {
    7667                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    7668                    if (match || preserveAllTokens) {
    7669                        lastMatch = true;
    7670                        if (sizePlus1++ == max) {
    7671                            i = len;
    7672                            lastMatch = false;
    7673                        }
    7674                        list.add(str.substring(start, i));
    7675                        match = false;
    7676                    }
    7677                    start = ++i;
    7678                    continue;
    7679                }
    7680                lastMatch = false;
    7681                match = true;
    7682                i++;
    7683            }
    7684        }
    7685        if (match || preserveAllTokens && lastMatch) {
    7686            list.add(str.substring(start, i));
    7687        }
    7688        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7689    }
    7690
    7691    /**
    7692     * Tests if a CharSequence starts with a specified prefix.
    7693     *
    7694     * <p>
    7695     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
    7696     * </p>
    7697     *
    7698     * <pre>
    7699     * StringUtils.startsWith(null, null)      = true
    7700     * StringUtils.startsWith(null, "abc")     = false
    7701     * StringUtils.startsWith("abcdef", null)  = false
    7702     * StringUtils.startsWith("abcdef", "abc") = true
    7703     * StringUtils.startsWith("ABCDEF", "abc") = false
    7704     * </pre>
    7705     *
    7706     * @param str    the CharSequence to check, may be null.
    7707     * @param prefix the prefix to find, may be null.
    7708     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or both {@code null}.
    7709     * @see String#startsWith(String)
    7710     * @since 2.4
    7711     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
    7712     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}
    7713     */
    7714    @Deprecated
    7715    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
    7716        return Strings.CS.startsWith(str, prefix);
    7717    }
    7718
    7719    /**
    7720     * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
    7721     *
    7722     * <pre>
    7723     * StringUtils.startsWithAny(null, null)      = false
    7724     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    7725     * StringUtils.startsWithAny("abcxyz", null)     = false
    7726     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
    7727     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    7728     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    7729     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
    7730     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
    7731     * </pre>
    7732     *
    7733     * @param sequence      the CharSequence to check, may be null.
    7734     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}.
    7735     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} begins with
    7736     *         any of the provided case-sensitive {@code searchStrings}.
    7737     * @see StringUtils#startsWith(CharSequence, CharSequence)
    7738     * @since 2.5
    7739     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
    7740     * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CS.startsWithAny(CharSequence, CharSequence...)}
    7741     */
    7742    @Deprecated
    7743    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    7744        return Strings.CS.startsWithAny(sequence, searchStrings);
    7745    }
    7746
    7747    /**
    7748     * Case-insensitive check if a CharSequence starts with a specified prefix.
    7749     *
    7750     * <p>
    7751     * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
    7752     * </p>
    7753     *
    7754     * <pre>
    7755     * StringUtils.startsWithIgnoreCase(null, null)      = true
    7756     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    7757     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    7758     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    7759     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    7760     * </pre>
    7761     *
    7762     * @param str    the CharSequence to check, may be null.
    7763     * @param prefix the prefix to find, may be null.
    7764     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or both {@code null}.
    7765     * @see String#startsWith(String)
    7766     * @since 2.4
    7767     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
    7768     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}
    7769     */
    7770    @Deprecated
    7771    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
    7772        return Strings.CI.startsWith(str, prefix);
    7773    }
    7774
    7775    /**
    7776     * Strips whitespace from the start and end of a String.
    7777     *
    7778     * <p>
    7779     * This is similar to {@link #trim(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
    7780     * </p>
    7781     *
    7782     * <p>
    7783     * A {@code null} input String returns {@code null}.
    7784     * </p>
    7785     *
    7786     * <pre>
    7787     * StringUtils.strip(null)     = null
    7788     * StringUtils.strip("")       = ""
    7789     * StringUtils.strip("   ")    = ""
    7790     * StringUtils.strip("abc")    = "abc"
    7791     * StringUtils.strip("  abc")  = "abc"
    7792     * StringUtils.strip("abc  ")  = "abc"
    7793     * StringUtils.strip(" abc ")  = "abc"
    7794     * StringUtils.strip(" ab c ") = "ab c"
    7795     * </pre>
    7796     *
    7797     * @param str the String to remove whitespace from, may be null.
    7798     * @return the stripped String, {@code null} if null String input.
    7799     */
    7800    public static String strip(final String str) {
    7801        return strip(str, null);
    7802    }
    7803
    7804    /**
    7805     * 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
    7806     * to be controlled.
    7807     *
    7808     * <p>
    7809     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
    7810     * </p>
    7811     *
    7812     * <p>
    7813     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}. Alternatively use
    7814     * {@link #strip(String)}.
    7815     * </p>
    7816     *
    7817     * <pre>
    7818     * StringUtils.strip(null, *)          = null
    7819     * StringUtils.strip("", *)            = ""
    7820     * StringUtils.strip("abc", null)      = "abc"
    7821     * StringUtils.strip("  abc", null)    = "abc"
    7822     * StringUtils.strip("abc  ", null)    = "abc"
    7823     * StringUtils.strip(" abc ", null)    = "abc"
    7824     * StringUtils.strip("  abcyx", "xyz") = "  abc"
    7825     * </pre>
    7826     *
    7827     * @param str        the String to remove characters from, may be null.
    7828     * @param stripChars the characters to remove, null treated as whitespace.
    7829     * @return the stripped String, {@code null} if null String input.
    7830     */
    7831    public static String strip(String str, final String stripChars) {
    7832        str = stripStart(str, stripChars);
    7833        return stripEnd(str, stripChars);
    7834    }
    7835
    7836    /**
    7837     * Removes diacritics (~= accents) from a string. The case will not be altered.
    7838     * <p>
    7839     * For instance, '&agrave;' will be replaced by 'a'.
    7840     * </p>
    7841     * <p>
    7842     * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
    7843     * </p>
    7844     *
    7845     * <pre>
    7846     * StringUtils.stripAccents(null)         = null
    7847     * StringUtils.stripAccents("")           = ""
    7848     * StringUtils.stripAccents("control")    = "control"
    7849     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
    7850     * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
    7851     * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
    7852     * </pre>
    7853     * <p>
    7854     * See also <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
    7855     * </p>
    7856     *
    7857     * @param input String to be stripped.
    7858     * @return input text with diacritics removed.
    7859     * @since 3.0
    7860     */
    7861    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix:
    7862    // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
    7863    public static String stripAccents(final String input) {
    7864        if (isEmpty(input)) {
    7865            return input;
    7866        }
    7867        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
    7868        convertRemainingAccentCharacters(decomposed);
    7869        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
    7870    }
    7871
    7872    /**
    7873     * Strips whitespace from the start and end of every String in an array. Whitespace is defined by {@link Character#isWhitespace(char)}.
    7874     *
    7875     * <p>
    7876     * A new array is returned each time, except for length zero. A {@code null} array will return {@code null}. An empty array will return itself. A
    7877     * {@code null} array entry will be ignored.
    7878     * </p>
    7879     *
    7880     * <pre>
    7881     * StringUtils.stripAll(null)             = null
    7882     * StringUtils.stripAll([])               = []
    7883     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    7884     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    7885     * </pre>
    7886     *
    7887     * @param strs the array to remove whitespace from, may be null.
    7888     * @return the stripped Strings, {@code null} if null array input.
    7889     */
    7890    public static String[] stripAll(final String... strs) {
    7891        return stripAll(strs, null);
    7892    }
    7893
    7894    /**
    7895     * Strips any of a set of characters from the start and end of every String in an array.
    7896     * <p>
    7897     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7898     * </p>
    7899     *
    7900     * <p>
    7901     * A new array is returned each time, except for length zero. A {@code null} array will return {@code null}. An empty array will return itself. A
    7902     * {@code null} array entry will be ignored. A {@code null} stripChars will strip whitespace as defined by {@link Character#isWhitespace(char)}.
    7903     * </p>
    7904     *
    7905     * <pre>
    7906     * StringUtils.stripAll(null, *)                = null
    7907     * StringUtils.stripAll([], *)                  = []
    7908     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    7909     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    7910     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    7911     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    7912     * </pre>
    7913     *
    7914     * @param strs       the array to remove characters from, may be null.
    7915     * @param stripChars the characters to remove, null treated as whitespace.
    7916     * @return the stripped Strings, {@code null} if null array input.
    7917     */
    7918    public static String[] stripAll(final String[] strs, final String stripChars) {
    7919        final int strsLen = ArrayUtils.getLength(strs);
    7920        if (strsLen == 0) {
    7921            return strs;
    7922        }
    7923        return ArrayUtils.setAll(new String[strsLen], i -> strip(strs[i], stripChars));
    7924    }
    7925
    7926    /**
    7927     * Strips any of a set of characters from the end of a String.
    7928     *
    7929     * <p>
    7930     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
    7931     * </p>
    7932     *
    7933     * <p>
    7934     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
    7935     * </p>
    7936     *
    7937     * <pre>
    7938     * StringUtils.stripEnd(null, *)          = null
    7939     * StringUtils.stripEnd("", *)            = ""
    7940     * StringUtils.stripEnd("abc", "")        = "abc"
    7941     * StringUtils.stripEnd("abc", null)      = "abc"
    7942     * StringUtils.stripEnd("  abc", null)    = "  abc"
    7943     * StringUtils.stripEnd("abc  ", null)    = "abc"
    7944     * StringUtils.stripEnd(" abc ", null)    = " abc"
    7945     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    7946     * StringUtils.stripEnd("120.00", ".0")   = "12"
    7947     * </pre>
    7948     *
    7949     * @param str        the String to remove characters from, may be null.
    7950     * @param stripChars the set of characters to remove, null treated as whitespace.
    7951     * @return the stripped String, {@code null} if null String input.
    7952     */
    7953    public static String stripEnd(final String str, final String stripChars) {
    7954        int end = length(str);
    7955        if (end == 0) {
    7956            return str;
    7957        }
    7958        if (stripChars == null) {
    7959            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
    7960                end--;
    7961            }
    7962        } else if (stripChars.isEmpty()) {
    7963            return str;
    7964        } else {
    7965            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
    7966                end--;
    7967            }
    7968        }
    7969        return str.substring(0, end);
    7970    }
    7971
    7972    /**
    7973     * Strips any of a set of characters from the start of a String.
    7974     *
    7975     * <p>
    7976     * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
    7977     * </p>
    7978     *
    7979     * <p>
    7980     * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
    7981     * </p>
    7982     *
    7983     * <pre>
    7984     * StringUtils.stripStart(null, *)          = null
    7985     * StringUtils.stripStart("", *)            = ""
    7986     * StringUtils.stripStart("abc", "")        = "abc"
    7987     * StringUtils.stripStart("abc", null)      = "abc"
    7988     * StringUtils.stripStart("  abc", null)    = "abc"
    7989     * StringUtils.stripStart("abc  ", null)    = "abc  "
    7990     * StringUtils.stripStart(" abc ", null)    = "abc "
    7991     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    7992     * </pre>
    7993     *
    7994     * @param str        the String to remove characters from, may be null.
    7995     * @param stripChars the characters to remove, null treated as whitespace.
    7996     * @return the stripped String, {@code null} if null String input.
    7997     */
    7998    public static String stripStart(final String str, final String stripChars) {
    7999        final int strLen = length(str);
    8000        if (strLen == 0) {
    8001            return str;
    8002        }
    8003        int start = 0;
    8004        if (stripChars == null) {
    8005            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
    8006                start++;
    8007            }
    8008        } else if (stripChars.isEmpty()) {
    8009            return str;
    8010        } else {
    8011            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
    8012                start++;
    8013            }
    8014        }
    8015        return str.substring(start);
    8016    }
    8017
    8018    /**
    8019     * Strips whitespace from the start and end of a String returning an empty String if {@code null} input.
    8020     *
    8021     * <p>
    8022     * This is similar to {@link #trimToEmpty(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
    8023     * </p>
    8024     *
    8025     * <pre>
    8026     * StringUtils.stripToEmpty(null)     = ""
    8027     * StringUtils.stripToEmpty("")       = ""
    8028     * StringUtils.stripToEmpty("   ")    = ""
    8029     * StringUtils.stripToEmpty("abc")    = "abc"
    8030     * StringUtils.stripToEmpty("  abc")  = "abc"
    8031     * StringUtils.stripToEmpty("abc  ")  = "abc"
    8032     * StringUtils.stripToEmpty(" abc ")  = "abc"
    8033     * StringUtils.stripToEmpty(" ab c ") = "ab c"
    8034     * </pre>
    8035     *
    8036     * @param str the String to be stripped, may be null.
    8037     * @return the trimmed String, or an empty String if {@code null} input.
    8038     * @since 2.0
    8039     */
    8040    public static String stripToEmpty(final String str) {
    8041        return str == null ? EMPTY : strip(str, null);
    8042    }
    8043
    8044    /**
    8045     * Strips whitespace from the start and end of a String returning {@code null} if the String is empty ("") after the strip.
    8046     *
    8047     * <p>
    8048     * This is similar to {@link #trimToNull(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
    8049     * </p>
    8050     *
    8051     * <pre>
    8052     * StringUtils.stripToNull(null)     = null
    8053     * StringUtils.stripToNull("")       = null
    8054     * StringUtils.stripToNull("   ")    = null
    8055     * StringUtils.stripToNull("abc")    = "abc"
    8056     * StringUtils.stripToNull("  abc")  = "abc"
    8057     * StringUtils.stripToNull("abc  ")  = "abc"
    8058     * StringUtils.stripToNull(" abc ")  = "abc"
    8059     * StringUtils.stripToNull(" ab c ") = "ab c"
    8060     * </pre>
    8061     *
    8062     * @param str the String to be stripped, may be null.
    8063     * @return the stripped String, {@code null} if whitespace, empty or null String input.
    8064     * @since 2.0
    8065     */
    8066    public static String stripToNull(String str) {
    8067        if (str == null) {
    8068            return null;
    8069        }
    8070        str = strip(str, null);
    8071        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
    8072    }
    8073
    8074    /**
    8075     * Gets a substring from the specified String avoiding exceptions.
    8076     *
    8077     * <p>
    8078     * A negative start position can be used to start {@code n} characters from the end of the String.
    8079     * </p>
    8080     *
    8081     * <p>
    8082     * A {@code null} String will return {@code null}. An empty ("") String will return "".
    8083     * </p>
    8084     *
    8085     * <pre>
    8086     * StringUtils.substring(null, *)   = null
    8087     * StringUtils.substring("", *)     = ""
    8088     * StringUtils.substring("abc", 0)  = "abc"
    8089     * StringUtils.substring("abc", 2)  = "c"
    8090     * StringUtils.substring("abc", 4)  = ""
    8091     * StringUtils.substring("abc", -2) = "bc"
    8092     * StringUtils.substring("abc", -4) = "abc"
    8093     * </pre>
    8094     *
    8095     * @param str   the String to get the substring from, may be null.
    8096     * @param start the position to start from, negative means count back from the end of the String by this many characters.
    8097     * @return substring from start position, {@code null} if null String input.
    8098     */
    8099    public static String substring(final String str, int start) {
    8100        if (str == null) {
    8101            return null;
    8102        }
    8103        // handle negatives, which means last n characters
    8104        if (start < 0) {
    8105            start = str.length() + start; // remember start is negative
    8106        }
    8107        if (start < 0) {
    8108            start = 0;
    8109        }
    8110        if (start > str.length()) {
    8111            return EMPTY;
    8112        }
    8113        return str.substring(start);
    8114    }
    8115
    8116    /**
    8117     * Gets a substring from the specified String avoiding exceptions.
    8118     *
    8119     * <p>
    8120     * A negative start position can be used to start/end {@code n} characters from the end of the String.
    8121     * </p>
    8122     *
    8123     * <p>
    8124     * The returned substring starts with the character in the {@code start} position and ends before the {@code end} position. All position counting is
    8125     * zero-based -- i.e., to start at the beginning of the string use {@code start = 0}. Negative start and end positions can be used to specify offsets
    8126     * relative to the end of the String.
    8127     * </p>
    8128     *
    8129     * <p>
    8130     * If {@code start} is not strictly to the left of {@code end}, "" is returned.
    8131     * </p>
    8132     *
    8133     * <pre>
    8134     * StringUtils.substring(null, *, *)    = null
    8135     * StringUtils.substring("", * ,  *)    = "";
    8136     * StringUtils.substring("abc", 0, 2)   = "ab"
    8137     * StringUtils.substring("abc", 2, 0)   = ""
    8138     * StringUtils.substring("abc", 2, 4)   = "c"
    8139     * StringUtils.substring("abc", 4, 6)   = ""
    8140     * StringUtils.substring("abc", 2, 2)   = ""
    8141     * StringUtils.substring("abc", -2, -1) = "b"
    8142     * StringUtils.substring("abc", -4, 2)  = "ab"
    8143     * </pre>
    8144     *
    8145     * @param str   the String to get the substring from, may be null.
    8146     * @param start the position to start from, negative means count back from the end of the String by this many characters.
    8147     * @param end   the position to end at (exclusive), negative means count back from the end of the String by this many characters.
    8148     * @return substring from start position to end position, {@code null} if null String input.
    8149     */
    8150    public static String substring(final String str, int start, int end) {
    8151        if (str == null) {
    8152            return null;
    8153        }
    8154        // handle negatives
    8155        if (end < 0) {
    8156            end = str.length() + end; // remember end is negative
    8157        }
    8158        if (start < 0) {
    8159            start = str.length() + start; // remember start is negative
    8160        }
    8161        // check length next
    8162        if (end > str.length()) {
    8163            end = str.length();
    8164        }
    8165        // if start is greater than end, return ""
    8166        if (start > end) {
    8167            return EMPTY;
    8168        }
    8169        if (start < 0) {
    8170            start = 0;
    8171        }
    8172        if (end < 0) {
    8173            end = 0;
    8174        }
    8175        return str.substring(start, end);
    8176    }
    8177
    8178    /**
    8179     * Gets the substring after the first occurrence of a separator. The separator is not returned.
    8180     *
    8181     * <p>
    8182     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8183     *
    8184     * <p>
    8185     * If nothing is found, the empty string is returned.
    8186     * </p>
    8187     *
    8188     * <pre>
    8189     * StringUtils.substringAfter(null, *)      = null
    8190     * StringUtils.substringAfter("", *)        = ""
    8191     * StringUtils.substringAfter("abc", 'a')   = "bc"
    8192     * StringUtils.substringAfter("abcba", 'b') = "cba"
    8193     * StringUtils.substringAfter("abc", 'c')   = ""
    8194     * StringUtils.substringAfter("abc", 'd')   = ""
    8195     * StringUtils.substringAfter(" abc", 32)   = "abc"
    8196     * </pre>
    8197     *
    8198     * @param str       the String to get a substring from, may be null.
    8199     * @param find the character (Unicode code point) to find.
    8200     * @return the substring after the first occurrence of the specified character, {@code null} if null String input.
    8201     * @since 3.11
    8202     */
    8203    public static String substringAfter(final String str, final int find) {
    8204        if (isEmpty(str)) {
    8205            return str;
    8206        }
    8207        final int pos = str.indexOf(find);
    8208        if (pos == INDEX_NOT_FOUND) {
    8209            return EMPTY;
    8210        }
    8211        return str.substring(pos + 1);
    8212    }
    8213
    8214    /**
    8215     * Gets the substring after the first occurrence of a separator. The separator is not returned.
    8216     *
    8217     * <p>
    8218     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. A {@code null} separator will return the
    8219     * empty string if the input string is not {@code null}.
    8220     * </p>
    8221     *
    8222     * <p>
    8223     * If nothing is found, the empty string is returned.
    8224     * </p>
    8225     *
    8226     * <pre>
    8227     * StringUtils.substringAfter(null, *)      = null
    8228     * StringUtils.substringAfter("", *)        = ""
    8229     * StringUtils.substringAfter(*, null)      = ""
    8230     * StringUtils.substringAfter("abc", "a")   = "bc"
    8231     * StringUtils.substringAfter("abcba", "b") = "cba"
    8232     * StringUtils.substringAfter("abc", "c")   = ""
    8233     * StringUtils.substringAfter("abc", "d")   = ""
    8234     * StringUtils.substringAfter("abc", "")    = "abc"
    8235     * </pre>
    8236     *
    8237     * @param str       the String to get a substring from, may be null.
    8238     * @param find the String to find, may be null.
    8239     * @return the substring after the first occurrence of the specified string, {@code null} if null String input.
    8240     * @since 2.0
    8241     */
    8242    public static String substringAfter(final String str, final String find) {
    8243        if (isEmpty(str)) {
    8244            return str;
    8245        }
    8246        if (find == null) {
    8247            return EMPTY;
    8248        }
    8249        final int pos = str.indexOf(find);
    8250        if (pos == INDEX_NOT_FOUND) {
    8251            return EMPTY;
    8252        }
    8253        return str.substring(pos + find.length());
    8254    }
    8255
    8256    /**
    8257     * Gets the substring after the last occurrence of a separator. The separator is not returned.
    8258     *
    8259     * <p>
    8260     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8261     *
    8262     * <p>
    8263     * If nothing is found, the empty string is returned.
    8264     * </p>
    8265     *
    8266     * <pre>
    8267     * StringUtils.substringAfterLast(null, *)      = null
    8268     * StringUtils.substringAfterLast("", *)        = ""
    8269     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
    8270     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
    8271     * StringUtils.substringAfterLast("abcba", 'b') = "a"
    8272     * StringUtils.substringAfterLast("abc", 'c')   = ""
    8273     * StringUtils.substringAfterLast("a", 'a')     = ""
    8274     * StringUtils.substringAfterLast("a", 'z')     = ""
    8275     * </pre>
    8276     *
    8277     * @param str       the String to get a substring from, may be null.
    8278     * @param find the character (Unicode code point) to find.
    8279     * @return the substring after the last occurrence of the specified character, {@code null} if null String input.
    8280     * @since 3.11
    8281     */
    8282    public static String substringAfterLast(final String str, final int find) {
    8283        if (isEmpty(str)) {
    8284            return str;
    8285        }
    8286        final int pos = str.lastIndexOf(find);
    8287        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
    8288            return EMPTY;
    8289        }
    8290        return str.substring(pos + 1);
    8291    }
    8292
    8293    /**
    8294     * Gets the substring after the last occurrence of a separator. The separator is not returned.
    8295     *
    8296     * <p>
    8297     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. An empty or {@code null} separator will
    8298     * return the empty string if the input string is not {@code null}.
    8299     * </p>
    8300     *
    8301     * <p>
    8302     * If nothing is found, the empty string is returned.
    8303     * </p>
    8304     *
    8305     * <pre>
    8306     * StringUtils.substringAfterLast(null, *)      = null
    8307     * StringUtils.substringAfterLast("", *)        = ""
    8308     * StringUtils.substringAfterLast(*, "")        = ""
    8309     * StringUtils.substringAfterLast(*, null)      = ""
    8310     * StringUtils.substringAfterLast("abc", "a")   = "bc"
    8311     * StringUtils.substringAfterLast("abcba", "b") = "a"
    8312     * StringUtils.substringAfterLast("abc", "c")   = ""
    8313     * StringUtils.substringAfterLast("a", "a")     = ""
    8314     * StringUtils.substringAfterLast("a", "z")     = ""
    8315     * </pre>
    8316     *
    8317     * @param str       the String to get a substring from, may be null.
    8318     * @param find the String to find, may be null.
    8319     * @return the substring after the last occurrence of the specified string, {@code null} if null String input.
    8320     * @since 2.0
    8321     */
    8322    public static String substringAfterLast(final String str, final String find) {
    8323        if (isEmpty(str)) {
    8324            return str;
    8325        }
    8326        if (isEmpty(find)) {
    8327            return EMPTY;
    8328        }
    8329        final int pos = str.lastIndexOf(find);
    8330        if (pos == INDEX_NOT_FOUND || pos == str.length() - find.length()) {
    8331            return EMPTY;
    8332        }
    8333        return str.substring(pos + find.length());
    8334    }
    8335
    8336    /**
    8337     * Gets the substring before the first occurrence of a separator. The separator is not returned.
    8338     *
    8339     * <p>
    8340     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8341     * </p>
    8342     *
    8343     * <p>
    8344     * If nothing is found, the string input is returned.
    8345     * </p>
    8346     *
    8347     * <pre>
    8348     * StringUtils.substringBefore(null, *)      = null
    8349     * StringUtils.substringBefore("", *)        = ""
    8350     * StringUtils.substringBefore("abc", 'a')   = ""
    8351     * StringUtils.substringBefore("abcba", 'b') = "a"
    8352     * StringUtils.substringBefore("abc", 'c')   = "ab"
    8353     * StringUtils.substringBefore("abc", 'd')   = "abc"
    8354     * </pre>
    8355     *
    8356     * @param str       the String to get a substring from, may be null.
    8357     * @param find the character (Unicode code point) to find.
    8358     * @return the substring before the first occurrence of the specified character, {@code null} if null String input.
    8359     * @since 3.12.0
    8360     */
    8361    public static String substringBefore(final String str, final int find) {
    8362        if (isEmpty(str)) {
    8363            return str;
    8364        }
    8365        final int pos = str.indexOf(find);
    8366        if (pos == INDEX_NOT_FOUND) {
    8367            return str;
    8368        }
    8369        return str.substring(0, pos);
    8370    }
    8371
    8372    /**
    8373     * Gets the substring before the first occurrence of a separator. The separator is not returned.
    8374     *
    8375     * <p>
    8376     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. A {@code null} separator will return the
    8377     * input string.
    8378     * </p>
    8379     *
    8380     * <p>
    8381     * If nothing is found, the string input is returned.
    8382     * </p>
    8383     *
    8384     * <pre>
    8385     * StringUtils.substringBefore(null, *)      = null
    8386     * StringUtils.substringBefore("", *)        = ""
    8387     * StringUtils.substringBefore("abc", "a")   = ""
    8388     * StringUtils.substringBefore("abcba", "b") = "a"
    8389     * StringUtils.substringBefore("abc", "c")   = "ab"
    8390     * StringUtils.substringBefore("abc", "d")   = "abc"
    8391     * StringUtils.substringBefore("abc", "")    = ""
    8392     * StringUtils.substringBefore("abc", null)  = "abc"
    8393     * </pre>
    8394     *
    8395     * @param str       the String to get a substring from, may be null.
    8396     * @param find the String to find, may be null.
    8397     * @return the substring before the first occurrence of the specified string, {@code null} if null String input.
    8398     * @since 2.0
    8399     */
    8400    public static String substringBefore(final String str, final String find) {
    8401        if (isEmpty(str) || find == null) {
    8402            return str;
    8403        }
    8404        if (find.isEmpty()) {
    8405            return EMPTY;
    8406        }
    8407        final int pos = str.indexOf(find);
    8408        if (pos == INDEX_NOT_FOUND) {
    8409            return str;
    8410        }
    8411        return str.substring(0, pos);
    8412    }
    8413
    8414    /**
    8415     * Gets the substring before the last occurrence of a separator. The separator is not returned.
    8416     *
    8417     * <p>
    8418     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. An empty or {@code null} separator will
    8419     * return the input string.
    8420     * </p>
    8421     *
    8422     * <p>
    8423     * If nothing is found, the string input is returned.
    8424     * </p>
    8425     *
    8426     * <pre>
    8427     * StringUtils.substringBeforeLast(null, *)      = null
    8428     * StringUtils.substringBeforeLast("", *)        = ""
    8429     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    8430     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    8431     * StringUtils.substringBeforeLast("a", "a")     = ""
    8432     * StringUtils.substringBeforeLast("a", "z")     = "a"
    8433     * StringUtils.substringBeforeLast("a", null)    = "a"
    8434     * StringUtils.substringBeforeLast("a", "")      = "a"
    8435     * </pre>
    8436     *
    8437     * @param str       the String to get a substring from, may be null.
    8438     * @param find the String to find, may be null.
    8439     * @return the substring before the last occurrence of the specified string, {@code null} if null String input.
    8440     * @since 2.0
    8441     */
    8442    public static String substringBeforeLast(final String str, final String find) {
    8443        if (isEmpty(str) || isEmpty(find)) {
    8444            return str;
    8445        }
    8446        final int pos = str.lastIndexOf(find);
    8447        if (pos == INDEX_NOT_FOUND) {
    8448            return str;
    8449        }
    8450        return str.substring(0, pos);
    8451    }
    8452
    8453    /**
    8454     * Gets the String that is nested in between two instances of the same String.
    8455     *
    8456     * <p>
    8457     * A {@code null} input String returns {@code null}. A {@code null} tag returns {@code null}.
    8458     * </p>
    8459     *
    8460     * <pre>
    8461     * StringUtils.substringBetween(null, *)            = null
    8462     * StringUtils.substringBetween("", "")             = ""
    8463     * StringUtils.substringBetween("", "tag")          = null
    8464     * StringUtils.substringBetween("tagabctag", null)  = null
    8465     * StringUtils.substringBetween("tagabctag", "")    = ""
    8466     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    8467     * </pre>
    8468     *
    8469     * @param str the String containing the substring, may be null.
    8470     * @param tag the String before and after the substring, may be null.
    8471     * @return the substring, {@code null} if no match.
    8472     * @since 2.0
    8473     */
    8474    public static String substringBetween(final String str, final String tag) {
    8475        return substringBetween(str, tag, tag);
    8476    }
    8477
    8478    /**
    8479     * Gets the String that is nested in between two Strings. Only the first match is returned.
    8480     *
    8481     * <p>
    8482     * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open and close returns an
    8483     * empty string.
    8484     * </p>
    8485     *
    8486     * <pre>
    8487     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    8488     * StringUtils.substringBetween(null, *, *)          = null
    8489     * StringUtils.substringBetween(*, null, *)          = null
    8490     * StringUtils.substringBetween(*, *, null)          = null
    8491     * StringUtils.substringBetween("", "", "")          = ""
    8492     * StringUtils.substringBetween("", "", "]")         = null
    8493     * StringUtils.substringBetween("", "[", "]")        = null
    8494     * StringUtils.substringBetween("yabcz", "", "")     = ""
    8495     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    8496     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    8497     * </pre>
    8498     *
    8499     * @param str   the String containing the substring, may be null.
    8500     * @param open  the String before the substring, may be null.
    8501     * @param close the String after the substring, may be null.
    8502     * @return the substring, {@code null} if no match.
    8503     * @since 2.0
    8504     */
    8505    public static String substringBetween(final String str, final String open, final String close) {
    8506        if (!ObjectUtils.allNotNull(str, open, close)) {
    8507            return null;
    8508        }
    8509        final int start = str.indexOf(open);
    8510        if (start != INDEX_NOT_FOUND) {
    8511            final int end = str.indexOf(close, start + open.length());
    8512            if (end != INDEX_NOT_FOUND) {
    8513                return str.substring(start + open.length(), end);
    8514            }
    8515        }
    8516        return null;
    8517    }
    8518
    8519    /**
    8520     * Searches a String for substrings delimited by a start and end tag, returning all matching substrings in an array.
    8521     *
    8522     * <p>
    8523     * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open/close returns
    8524     * {@code null} (no match).
    8525     * </p>
    8526     *
    8527     * <pre>
    8528     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    8529     * StringUtils.substringsBetween(null, *, *)            = null
    8530     * StringUtils.substringsBetween(*, null, *)            = null
    8531     * StringUtils.substringsBetween(*, *, null)            = null
    8532     * StringUtils.substringsBetween("", "[", "]")          = []
    8533     * </pre>
    8534     *
    8535     * @param str   the String containing the substrings, null returns null, empty returns empty.
    8536     * @param open  the String identifying the start of the substring, empty returns null.
    8537     * @param close the String identifying the end of the substring, empty returns null.
    8538     * @return a String Array of substrings, or {@code null} if no match.
    8539     * @since 2.3
    8540     */
    8541    public static String[] substringsBetween(final String str, final String open, final String close) {
    8542        if (str == null || isEmpty(open) || isEmpty(close)) {
    8543            return null;
    8544        }
    8545        final int strLen = str.length();
    8546        if (strLen == 0) {
    8547            return ArrayUtils.EMPTY_STRING_ARRAY;
    8548        }
    8549        final int closeLen = close.length();
    8550        final int openLen = open.length();
    8551        final List<String> list = new ArrayList<>();
    8552        int pos = 0;
    8553        while (pos < strLen - closeLen) {
    8554            int start = str.indexOf(open, pos);
    8555            if (start < 0) {
    8556                break;
    8557            }
    8558            start += openLen;
    8559            final int end = str.indexOf(close, start);
    8560            if (end < 0) {
    8561                break;
    8562            }
    8563            list.add(str.substring(start, end));
    8564            pos = end + closeLen;
    8565        }
    8566        if (list.isEmpty()) {
    8567            return null;
    8568        }
    8569        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    8570    }
    8571
    8572    /**
    8573     * Swaps the case of a String changing upper and title case to lower case, and lower case to upper case.
    8574     *
    8575     * <ul>
    8576     * <li>Upper case character converts to Lower case</li>
    8577     * <li>Title case character converts to Lower case</li>
    8578     * <li>Lower case character converts to Upper case</li>
    8579     * </ul>
    8580     *
    8581     * <p>
    8582     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}. A {@code null} input String returns {@code null}.
    8583     * </p>
    8584     *
    8585     * <pre>
    8586     * StringUtils.swapCase(null)                 = null
    8587     * StringUtils.swapCase("")                   = ""
    8588     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    8589     * </pre>
    8590     *
    8591     * <p>
    8592     * 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
    8593     * functionality is available in org.apache.commons.lang3.text.WordUtils.
    8594     * </p>
    8595     *
    8596     * @param str the String to swap case, may be null.
    8597     * @return the changed String, {@code null} if null String input.
    8598     */
    8599    public static String swapCase(final String str) {
    8600        if (isEmpty(str)) {
    8601            return str;
    8602        }
    8603        final int strLen = str.length();
    8604        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    8605        int outOffset = 0;
    8606        for (int i = 0; i < strLen;) {
    8607            final int oldCodepoint = str.codePointAt(i);
    8608            final int newCodePoint;
    8609            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
    8610                newCodePoint = Character.toLowerCase(oldCodepoint);
    8611            } else if (Character.isLowerCase(oldCodepoint)) {
    8612                newCodePoint = Character.toUpperCase(oldCodepoint);
    8613            } else {
    8614                newCodePoint = oldCodepoint;
    8615            }
    8616            newCodePoints[outOffset++] = newCodePoint;
    8617            i += Character.charCount(newCodePoint);
    8618        }
    8619        return new String(newCodePoints, 0, outOffset);
    8620    }
    8621
    8622    /**
    8623     * Converts a {@link CharSequence} into an array of code points.
    8624     *
    8625     * <p>
    8626     * 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
    8627     * followed by a low surrogate or a low surrogate not preceded by a high surrogate) will be returned as-is.
    8628     * </p>
    8629     *
    8630     * <pre>
    8631     * StringUtils.toCodePoints(null)   =  null
    8632     * StringUtils.toCodePoints("")     =  []  // empty array
    8633     * </pre>
    8634     *
    8635     * @param cs the character sequence to convert.
    8636     * @return an array of code points.
    8637     * @since 3.6
    8638     */
    8639    public static int[] toCodePoints(final CharSequence cs) {
    8640        if (cs == null) {
    8641            return null;
    8642        }
    8643        if (cs.length() == 0) {
    8644            return ArrayUtils.EMPTY_INT_ARRAY;
    8645        }
    8646        return cs.toString().codePoints().toArray();
    8647    }
    8648
    8649    /**
    8650     * Converts a {@code byte[]} to a String using the specified character encoding.
    8651     *
    8652     * @param bytes   the byte array to read from.
    8653     * @param charset the encoding to use, if null then use the platform default.
    8654     * @return a new String.
    8655     * @throws NullPointerException if {@code bytes} is null
    8656     * @since 3.2
    8657     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
    8658     */
    8659    public static String toEncodedString(final byte[] bytes, final Charset charset) {
    8660        return new String(bytes, Charsets.toCharset(charset));
    8661    }
    8662
    8663    /**
    8664     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
    8665     *
    8666     * @param source A source String or null.
    8667     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
    8668     * @since 3.10
    8669     */
    8670    public static String toRootLowerCase(final String source) {
    8671        return source == null ? null : source.toLowerCase(Locale.ROOT);
    8672    }
    8673
    8674    /**
    8675     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
    8676     *
    8677     * @param source A source String or null.
    8678     * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
    8679     * @since 3.10
    8680     */
    8681    public static String toRootUpperCase(final String source) {
    8682        return source == null ? null : source.toUpperCase(Locale.ROOT);
    8683    }
    8684
    8685    /**
    8686     * Converts a {@code byte[]} to a String using the specified character encoding.
    8687     *
    8688     * @param bytes       the byte array to read from.
    8689     * @param charsetName the encoding to use, if null then use the platform default.
    8690     * @return a new String.
    8691     * @throws NullPointerException if the input is null.
    8692     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
    8693     * @since 3.1
    8694     */
    8695    @Deprecated
    8696    public static String toString(final byte[] bytes, final String charsetName) {
    8697        return new String(bytes, Charsets.toCharset(charsetName));
    8698    }
    8699
    8700    /**
    8701     * Removes control characters (char &lt;= 32) from both ends of this String, handling {@code null} by returning {@code null}.
    8702     *
    8703     * <p>
    8704     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #strip(String)}.
    8705     * </p>
    8706     *
    8707     * <p>
    8708     * To trim your choice of characters, use the {@link #strip(String, String)} methods.
    8709     * </p>
    8710     *
    8711     * <pre>
    8712     * StringUtils.trim(null)          = null
    8713     * StringUtils.trim("")            = ""
    8714     * StringUtils.trim("     ")       = ""
    8715     * StringUtils.trim("abc")         = "abc"
    8716     * StringUtils.trim("    abc    ") = "abc"
    8717     * </pre>
    8718     *
    8719     * @param str the String to be trimmed, may be null.
    8720     * @return the trimmed string, {@code null} if null String input.
    8721     */
    8722    public static String trim(final String str) {
    8723        return str == null ? null : str.trim();
    8724    }
    8725
    8726    /**
    8727     * Removes control characters (char &lt;= 32) from both ends of this String returning an empty String ("") if the String is empty ("") after the trim or if
    8728     * it is {@code null}.
    8729     *
    8730     * <p>
    8731     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToEmpty(String)}.
    8732     *
    8733     * <pre>
    8734     * StringUtils.trimToEmpty(null)          = ""
    8735     * StringUtils.trimToEmpty("")            = ""
    8736     * StringUtils.trimToEmpty("     ")       = ""
    8737     * StringUtils.trimToEmpty("abc")         = "abc"
    8738     * StringUtils.trimToEmpty("    abc    ") = "abc"
    8739     * </pre>
    8740     *
    8741     * @param str the String to be trimmed, may be null.
    8742     * @return the trimmed String, or an empty String if {@code null} input.
    8743     * @since 2.0
    8744     */
    8745    public static String trimToEmpty(final String str) {
    8746        return str == null ? EMPTY : str.trim();
    8747    }
    8748
    8749    /**
    8750     * Removes control characters (char &lt;= 32) from both ends of this String returning {@code null} if the String is empty ("") after the trim or if it is
    8751     * {@code null}.
    8752     *
    8753     * <p>
    8754     * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToNull(String)}.
    8755     *
    8756     * <pre>
    8757     * StringUtils.trimToNull(null)          = null
    8758     * StringUtils.trimToNull("")            = null
    8759     * StringUtils.trimToNull("     ")       = null
    8760     * StringUtils.trimToNull("abc")         = "abc"
    8761     * StringUtils.trimToNull("    abc    ") = "abc"
    8762     * </pre>
    8763     *
    8764     * @param str the String to be trimmed, may be null.
    8765     * @return the trimmed String, {@code null} if only chars &lt;= 32, empty or null String input.
    8766     * @since 2.0
    8767     */
    8768    public static String trimToNull(final String str) {
    8769        final String ts = trim(str);
    8770        return isEmpty(ts) ? null : ts;
    8771    }
    8772
    8773    /**
    8774     * Truncates a String. This will turn "Now is the time for all good men" into "Now is the time for".
    8775     *
    8776     * <p>
    8777     * Specifically:
    8778     * </p>
    8779     * <ul>
    8780     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
    8781     * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
    8782     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
    8783     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
    8784     * </ul>
    8785     *
    8786     * <pre>
    8787     * StringUtils.truncate(null, 0)       = null
    8788     * StringUtils.truncate(null, 2)       = null
    8789     * StringUtils.truncate("", 4)         = ""
    8790     * StringUtils.truncate("abcdefg", 4)  = "abcd"
    8791     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
    8792     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
    8793     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
    8794     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
    8795     * </pre>
    8796     *
    8797     * @param str      the String to truncate, may be null.
    8798     * @param maxWidth maximum length of result String, must be positive.
    8799     * @return truncated String, {@code null} if null String input.
    8800     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}.
    8801     * @since 3.5
    8802     */
    8803    public static String truncate(final String str, final int maxWidth) {
    8804        return truncate(str, 0, maxWidth);
    8805    }
    8806
    8807    /**
    8808     * Truncates a String. This will turn "Now is the time for all good men" into "is the time for all".
    8809     *
    8810     * <p>
    8811     * Works like {@code truncate(String, int)}, but allows you to specify a "left edge" offset.
    8812     *
    8813     * <p>
    8814     * Specifically:
    8815     * </p>
    8816     * <ul>
    8817     * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
    8818     * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
    8819     * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
    8820     * <li>If {@code offset} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
    8821     * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
    8822     * </ul>
    8823     *
    8824     * <pre>
    8825     * StringUtils.truncate(null, 0, 0) = null
    8826     * StringUtils.truncate(null, 2, 4) = null
    8827     * StringUtils.truncate("", 0, 10) = ""
    8828     * StringUtils.truncate("", 2, 10) = ""
    8829     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
    8830     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
    8831     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
    8832     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
    8833     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
    8834     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
    8835     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
    8836     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
    8837     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
    8838     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
    8839     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
    8840     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
    8841     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
    8842     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
    8843     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
    8844     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
    8845     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
    8846     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
    8847     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
    8848     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
    8849     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
    8850     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
    8851     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
    8852     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
    8853     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
    8854     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
    8855     * </pre>
    8856     *
    8857     * @param str      the String to truncate, may be null.
    8858     * @param offset   left edge of source String.
    8859     * @param maxWidth maximum length of result String, must be positive.
    8860     * @return truncated String, {@code null} if null String input.
    8861     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}.
    8862     * @since 3.5
    8863     */
    8864    public static String truncate(final String str, final int offset, final int maxWidth) {
    8865        if (offset < 0) {
    8866            throw new IllegalArgumentException("offset cannot be negative");
    8867        }
    8868        if (maxWidth < 0) {
    8869            throw new IllegalArgumentException("maxWith cannot be negative");
    8870        }
    8871        if (str == null) {
    8872            return null;
    8873        }
    8874        if (offset > str.length()) {
    8875            return EMPTY;
    8876        }
    8877        if (str.length() > maxWidth) {
    8878            final int ix = Math.min(offset + maxWidth, str.length());
    8879            return str.substring(offset, ix);
    8880        }
    8881        return str.substring(offset);
    8882    }
    8883
    8884    /**
    8885     * Uncapitalizes a String, changing the first character to lower case as per {@link Character#toLowerCase(int)}. No other characters are changed.
    8886     *
    8887     * <p>
    8888     * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}. A {@code null} input String returns {@code null}.
    8889     * </p>
    8890     *
    8891     * <pre>
    8892     * StringUtils.uncapitalize(null)  = null
    8893     * StringUtils.uncapitalize("")    = ""
    8894     * StringUtils.uncapitalize("cat") = "cat"
    8895     * StringUtils.uncapitalize("Cat") = "cat"
    8896     * StringUtils.uncapitalize("CAT") = "cAT"
    8897     * </pre>
    8898     *
    8899     * @param str the String to uncapitalize, may be null.
    8900     * @return the uncapitalized String, {@code null} if null String input.
    8901     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
    8902     * @see #capitalize(String)
    8903     * @since 2.0
    8904     */
    8905    public static String uncapitalize(final String str) {
    8906        final int strLen = length(str);
    8907        if (strLen == 0) {
    8908            return str;
    8909        }
    8910        final int firstCodePoint = str.codePointAt(0);
    8911        final int newCodePoint = Character.toLowerCase(firstCodePoint);
    8912        if (firstCodePoint == newCodePoint) {
    8913            // already uncapitalized
    8914            return str;
    8915        }
    8916        final int[] newCodePoints = str.codePoints().toArray();
    8917        newCodePoints[0] = newCodePoint; // copy the first code point
    8918        return new String(newCodePoints, 0, newCodePoints.length);
    8919    }
    8920
    8921    /**
    8922     * Unwraps a given string from a character.
    8923     *
    8924     * <pre>
    8925     * StringUtils.unwrap(null, null)         = null
    8926     * StringUtils.unwrap(null, '\0')         = null
    8927     * StringUtils.unwrap(null, '1')          = null
    8928     * StringUtils.unwrap("a", 'a')           = "a"
    8929     * StringUtils.unwrap("aa", 'a')           = ""
    8930     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
    8931     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
    8932     * StringUtils.unwrap("A", '#')           = "A"
    8933     * StringUtils.unwrap("#A", '#')          = "#A"
    8934     * StringUtils.unwrap("A#", '#')          = "A#"
    8935     * </pre>
    8936     *
    8937     * @param str      the String to be unwrapped, can be null.
    8938     * @param wrapChar the character used to unwrap.
    8939     * @return unwrapped String or the original string if it is not quoted properly with the wrapChar.
    8940     * @since 3.6
    8941     */
    8942    public static String unwrap(final String str, final char wrapChar) {
    8943        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
    8944            return str;
    8945        }
    8946        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
    8947            final int startIndex = 0;
    8948            final int endIndex = str.length() - 1;
    8949            return str.substring(startIndex + 1, endIndex);
    8950        }
    8951        return str;
    8952    }
    8953
    8954    /**
    8955     * Unwraps a given string from another string.
    8956     *
    8957     * <pre>
    8958     * StringUtils.unwrap(null, null)         = null
    8959     * StringUtils.unwrap(null, "")           = null
    8960     * StringUtils.unwrap(null, "1")          = null
    8961     * StringUtils.unwrap("a", "a")           = "a"
    8962     * StringUtils.unwrap("aa", "a")          = ""
    8963     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
    8964     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
    8965     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
    8966     * StringUtils.unwrap("A", "#")           = "A"
    8967     * StringUtils.unwrap("#A", "#")          = "#A"
    8968     * StringUtils.unwrap("A#", "#")          = "A#"
    8969     * </pre>
    8970     *
    8971     * @param str       the String to be unwrapped, can be null.
    8972     * @param wrapToken the String used to unwrap.
    8973     * @return unwrapped String or the original string if it is not quoted properly with the wrapToken.
    8974     * @since 3.6
    8975     */
    8976    public static String unwrap(final String str, final String wrapToken) {
    8977        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
    8978            return str;
    8979        }
    8980        if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
    8981            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
    8982        }
    8983        return str;
    8984    }
    8985
    8986    /**
    8987     * Converts a String to upper case as per {@link String#toUpperCase()}.
    8988     *
    8989     * <p>
    8990     * A {@code null} input String returns {@code null}.
    8991     * </p>
    8992     *
    8993     * <pre>
    8994     * StringUtils.upperCase(null)  = null
    8995     * StringUtils.upperCase("")    = ""
    8996     * StringUtils.upperCase("aBc") = "ABC"
    8997     * </pre>
    8998     *
    8999     * <p>
    9000     * <strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, the result of this method is affected by the current locale.
    9001     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)} should be used with a specific locale (e.g.
    9002     * {@link Locale#ENGLISH}).
    9003     * </p>
    9004     *
    9005     * @param str the String to upper case, may be null.
    9006     * @return the upper-cased String, {@code null} if null String input.
    9007     */
    9008    public static String upperCase(final String str) {
    9009        if (str == null) {
    9010            return null;
    9011        }
    9012        return str.toUpperCase();
    9013    }
    9014
    9015    /**
    9016     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
    9017     *
    9018     * <p>
    9019     * A {@code null} input String returns {@code null}.
    9020     * </p>
    9021     *
    9022     * <pre>
    9023     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    9024     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    9025     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    9026     * </pre>
    9027     *
    9028     * @param str    the String to upper case, may be null.
    9029     * @param locale the locale that defines the case transformation rules, must not be null.
    9030     * @return the upper-cased String, {@code null} if null String input.
    9031     * @since 2.5
    9032     */
    9033    public static String upperCase(final String str, final Locale locale) {
    9034        if (str == null) {
    9035            return null;
    9036        }
    9037        return str.toUpperCase(LocaleUtils.toLocale(locale));
    9038    }
    9039
    9040    /**
    9041     * Returns the string representation of the {@code char} array or null.
    9042     *
    9043     * @param value the character array.
    9044     * @return a String or null.
    9045     * @see String#valueOf(char[])
    9046     * @since 3.9
    9047     */
    9048    public static String valueOf(final char[] value) {
    9049        return value == null ? null : String.valueOf(value);
    9050    }
    9051
    9052    /**
    9053     * Wraps a string with a char.
    9054     *
    9055     * <pre>
    9056     * StringUtils.wrap(null, *)        = null
    9057     * StringUtils.wrap("", *)          = ""
    9058     * StringUtils.wrap("ab", '\0')     = "ab"
    9059     * StringUtils.wrap("ab", 'x')      = "xabx"
    9060     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9061     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
    9062     * </pre>
    9063     *
    9064     * @param str      the string to be wrapped, may be {@code null}.
    9065     * @param wrapWith the char that will wrap {@code str}.
    9066     * @return the wrapped string, or {@code null} if {@code str == null}.
    9067     * @since 3.4
    9068     */
    9069    public static String wrap(final String str, final char wrapWith) {
    9070        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9071            return str;
    9072        }
    9073        return wrapWith + str + wrapWith;
    9074    }
    9075
    9076    /**
    9077     * Wraps a String with another String.
    9078     *
    9079     * <p>
    9080     * A {@code null} input String returns {@code null}.
    9081     * </p>
    9082     *
    9083     * <pre>
    9084     * StringUtils.wrap(null, *)         = null
    9085     * StringUtils.wrap("", *)           = ""
    9086     * StringUtils.wrap("ab", null)      = "ab"
    9087     * StringUtils.wrap("ab", "x")       = "xabx"
    9088     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9089     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
    9090     * StringUtils.wrap("ab", "'")       = "'ab'"
    9091     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
    9092     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9093     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9094     * </pre>
    9095     *
    9096     * @param str      the String to be wrapper, may be null.
    9097     * @param wrapWith the String that will wrap str.
    9098     * @return wrapped String, {@code null} if null String input.
    9099     * @since 3.4
    9100     */
    9101    public static String wrap(final String str, final String wrapWith) {
    9102        if (isEmpty(str) || isEmpty(wrapWith)) {
    9103            return str;
    9104        }
    9105        return wrapWith.concat(str).concat(wrapWith);
    9106    }
    9107
    9108    /**
    9109     * Wraps a string with a char if that char is missing from the start or end of the given string.
    9110     *
    9111     * <p>
    9112     * A new {@link String} will not be created if {@code str} is already wrapped.
    9113     * </p>
    9114     *
    9115     * <pre>
    9116     * StringUtils.wrapIfMissing(null, *)        = null
    9117     * StringUtils.wrapIfMissing("", *)          = ""
    9118     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
    9119     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
    9120     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
    9121     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
    9122     * StringUtils.wrapIfMissing("/", '/')  = "/"
    9123     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
    9124     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
    9125     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
    9126     * </pre>
    9127     *
    9128     * @param str      the string to be wrapped, may be {@code null}.
    9129     * @param wrapWith the char that will wrap {@code str}.
    9130     * @return the wrapped string, or {@code null} if {@code str == null}.
    9131     * @since 3.5
    9132     */
    9133    public static String wrapIfMissing(final String str, final char wrapWith) {
    9134        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9135            return str;
    9136        }
    9137        final boolean wrapStart = str.charAt(0) != wrapWith;
    9138        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
    9139        if (!wrapStart && !wrapEnd) {
    9140            return str;
    9141        }
    9142        final StringBuilder builder = new StringBuilder(str.length() + 2);
    9143        if (wrapStart) {
    9144            builder.append(wrapWith);
    9145        }
    9146        builder.append(str);
    9147        if (wrapEnd) {
    9148            builder.append(wrapWith);
    9149        }
    9150        return builder.toString();
    9151    }
    9152
    9153    /**
    9154     * Wraps a string with a string if that string is missing from the start or end of the given string.
    9155     *
    9156     * <p>
    9157     * A new {@link String} will not be created if {@code str} is already wrapped.
    9158     * </p>
    9159     *
    9160     * <pre>
    9161     * StringUtils.wrapIfMissing(null, *)         = null
    9162     * StringUtils.wrapIfMissing("", *)           = ""
    9163     * StringUtils.wrapIfMissing("ab", null)      = "ab"
    9164     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
    9165     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
    9166     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
    9167     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
    9168     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
    9169     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
    9170     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
    9171     * StringUtils.wrapIfMissing("/", "/")  = "/"
    9172     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
    9173     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
    9174     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
    9175     * </pre>
    9176     *
    9177     * @param str      the string to be wrapped, may be {@code null}.
    9178     * @param wrapWith the string that will wrap {@code str}.
    9179     * @return the wrapped string, or {@code null} if {@code str == null}.
    9180     * @since 3.5
    9181     */
    9182    public static String wrapIfMissing(final String str, final String wrapWith) {
    9183        if (isEmpty(str) || isEmpty(wrapWith)) {
    9184            return str;
    9185        }
    9186        final boolean wrapStart = !str.startsWith(wrapWith);
    9187        final boolean wrapEnd = !str.endsWith(wrapWith);
    9188        if (!wrapStart && !wrapEnd) {
    9189            return str;
    9190        }
    9191        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
    9192        if (wrapStart) {
    9193            builder.append(wrapWith);
    9194        }
    9195        builder.append(str);
    9196        if (wrapEnd) {
    9197            builder.append(wrapWith);
    9198        }
    9199        return builder.toString();
    9200    }
    9201
    9202    /**
    9203     * {@link StringUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as {@code StringUtils.trim(" foo ");}.
    9204     *
    9205     * <p>
    9206     * This constructor is public to permit tools that require a JavaBean instance to operate.
    9207     * </p>
    9208     *
    9209     * @deprecated TODO Make private in 4.0.
    9210     */
    9211    @Deprecated
    9212    public StringUtils() {
    9213        // empty
    9214    }
    9215
    9216}