    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
    242     * "Now is the time for all good men" into "...is the time for..."
    243     *
    244     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
    245     * a "left edge" offset.  Note that this left edge is not necessarily going to
    246     * be the leftmost character in the result, or the first character following the
    247     * ellipses, but it will appear somewhere in the result.
    248     *
    249     * <p>In no case will it return a String of length greater than
    250     * {@code maxWidth}.</p>
    251     *
    252     * <pre>
    253     * StringUtils.abbreviate(null, *, *)                = null
    254     * StringUtils.abbreviate("", 0, 4)                  = ""
    255     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
    256     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
    257     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
    258     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
    259     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
    260     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
    261     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
    262     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
    263     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
    264     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
    265     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
    266     * </pre>
    267     *
    268     * @param str  the String to check, may be null
    269     * @param offset  left edge of source String
    270     * @param maxWidth  maximum length of result String, must be at least 4
    271     * @return abbreviated String, {@code null} if null String input
    272     * @throws IllegalArgumentException if the width is too small
    273     * @since 2.0
    274     */
    275    public static String abbreviate(final String str, final int offset, final int maxWidth) {
    276        return abbreviate(str, ELLIPSIS3, offset, maxWidth);
    277    }
    278
    279    /**
    280     * Abbreviates a String using another given String as replacement marker. This will turn
    281     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
    282     * as the replacement marker.
    283     *
    284     * <p>Specifically:</p>
    285     * <ul>
    286     *   <li>If the number of characters in {@code str} is less than or equal to
    287     *       {@code maxWidth}, return {@code str}.</li>
    288     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
    289     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
    290     *       {@link IllegalArgumentException}.</li>
    291     *   <li>In no case will it return a String of length greater than
    292     *       {@code maxWidth}.</li>
    293     * </ul>
    294     *
    295     * <pre>
    296     * StringUtils.abbreviate(null, "...", *)      = null
    297     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
    298     * StringUtils.abbreviate("", "...", 4)        = ""
    299     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
    300     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
    301     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
    302     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
    303     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
    304     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
    305     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
    306     * </pre>
    307     *
    308     * @param str  the String to check, may be null
    309     * @param abbrevMarker  the String used as replacement marker
    310     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
    311     * @return abbreviated String, {@code null} if null String input
    312     * @throws IllegalArgumentException if the width is too small
    313     * @since 3.6
    314     */
    315    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
    316        return abbreviate(str, abbrevMarker, 0, maxWidth);
    317    }
    318    /**
    319     * Abbreviates a String using a given replacement marker. This will turn
    320     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
    321     * as the replacement marker.
    322     *
    323     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
    324     * a "left edge" offset.  Note that this left edge is not necessarily going to
    325     * be the leftmost character in the result, or the first character following the
    326     * replacement marker, but it will appear somewhere in the result.
    327     *
    328     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
    329     *
    330     * <pre>
    331     * StringUtils.abbreviate(null, null, *, *)                 = null
    332     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
    333     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
    334     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
    335     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
    336     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
    337     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
    338     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
    339     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
    340     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
    341     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
    342     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
    343     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
    344     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
    345     * </pre>
    346     *
    347     * @param str  the String to check, may be null
    348     * @param abbrevMarker  the String used as replacement marker
    349     * @param offset  left edge of source String
    350     * @param maxWidth  maximum length of result String, must be at least 4
    351     * @return abbreviated String, {@code null} if null String input
    352     * @throws IllegalArgumentException if the width is too small
    353     * @since 3.6
    354     */
    355    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
    356        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
    357            return substring(str, 0, maxWidth);
    358        }
    359        if (isAnyEmpty(str, abbrevMarker)) {
    360            return str;
    361        }
    362        final int abbrevMarkerLength = abbrevMarker.length();
    363        final int minAbbrevWidth = abbrevMarkerLength + 1;
    364        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
    365
    366        if (maxWidth < minAbbrevWidth) {
    367            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
    368        }
    369        final int strLen = str.length();
    370        if (strLen <= maxWidth) {
    371            return str;
    372        }
    373        if (offset > strLen) {
    374            offset = strLen;
    375        }
    376        if (strLen - offset < maxWidth - abbrevMarkerLength) {
    377            offset = strLen - (maxWidth - abbrevMarkerLength);
    378        }
    379        if (offset <= abbrevMarkerLength + 1) {
    380            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
    381        }
    382        if (maxWidth < minAbbrevWidthOffset) {
    383            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
    384        }
    385        if (offset + maxWidth - abbrevMarkerLength < strLen) {
    386            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
    387        }
    388        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
    389    }
    390
    391    /**
    392     * Abbreviates a String to the length passed, replacing the middle characters with the supplied
    393     * replacement String.
    394     *
    395     * <p>This abbreviation only occurs if the following criteria is met:</p>
    396     * <ul>
    397     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
    398     * <li>The length to truncate to is less than the length of the supplied String</li>
    399     * <li>The length to truncate to is greater than 0</li>
    400     * <li>The abbreviated String will have enough room for the length supplied replacement String
    401     * and the first and last characters of the supplied String for abbreviation</li>
    402     * </ul>
    403     * <p>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
    510     * per {@link Character#toTitleCase(int)}. No other characters are changed.
    511     *
    512     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
    513     * A {@code null} input String returns {@code null}.</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}
    546     * using the space character (' ').
    547     *
    548     * <p>If the size is less than the String length, the original String is returned.
    549     * A {@code null} String returns {@code null}.
    550     * A negative size is treated as zero.</p>
    551     *
    552     * <p>Equivalent to {@code center(str, size, " ")}.</p>
    553     *
    554     * <pre>
    555     * StringUtils.center(null, *)   = null
    556     * StringUtils.center("", 4)     = "    "
    557     * StringUtils.center("ab", -1)  = "ab"
    558     * StringUtils.center("ab", 4)   = " ab "
    559     * StringUtils.center("abcd", 2) = "abcd"
    560     * StringUtils.center("a", 4)    = " a  "
    561     * </pre>
    562     *
    563     * @param str  the String to center, may be null
    564     * @param size  the int size of new String, negative treated as zero
    565     * @return centered String, {@code null} if null String input
    566     */
    567    public static String center(final String str, final int size) {
    568        return center(str, size, ' ');
    569    }
    570
    571    /**
    572     * Centers a String in a larger String of size {@code size}.
    573     * Uses a supplied character as the value to pad the String with.
    574     *
    575     * <p>If the size is less than the String length, the String is returned.
    576     * A {@code null} String returns {@code null}.
    577     * A negative size is treated as zero.</p>
    578     *
    579     * <pre>
    580     * StringUtils.center(null, *, *)     = null
    581     * StringUtils.center("", 4, ' ')     = "    "
    582     * StringUtils.center("ab", -1, ' ')  = "ab"
    583     * StringUtils.center("ab", 4, ' ')   = " ab "
    584     * StringUtils.center("abcd", 2, ' ') = "abcd"
    585     * StringUtils.center("a", 4, ' ')    = " a  "
    586     * StringUtils.center("a", 4, 'y')    = "yayy"
    587     * </pre>
    588     *
    589     * @param str  the String to center, may be null
    590     * @param size  the int size of new String, negative treated as zero
    591     * @param padChar  the character to pad the new String with
    592     * @return centered String, {@code null} if null String input
    593     * @since 2.0
    594     */
    595    public static String center(String str, final int size, final char padChar) {
    596        if (str == null || size <= 0) {
    597            return str;
    598        }
    599        final int strLen = str.length();
    600        final int pads = size - strLen;
    601        if (pads <= 0) {
    602            return str;
    603        }
    604        str = leftPad(str, strLen + pads / 2, padChar);
    605        return rightPad(str, size, padChar);
    606    }
    607
    608    /**
    609     * Centers a String in a larger String of size {@code size}.
    610     * Uses a supplied String as the value to pad the String with.
    611     *
    612     * <p>If the size is less than the String length, the String is returned.
    613     * A {@code null} String returns {@code null}.
    614     * A negative size is treated as zero.</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,
    652     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
    653     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
    654     *
    655     * <p>NOTE: This method changed in 2.0.
    656     * It now more closely matches Perl chomp.</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
    680        if (str.length() == 1) {
    681            final char ch = str.charAt(0);
    682            if (ch == CharUtils.CR || ch == CharUtils.LF) {
    683                return EMPTY;
    684            }
    685            return str;
    686        }
    687
    688        int lastIdx = str.length() - 1;
    689        final char last = str.charAt(lastIdx);
    690
    691        if (last == CharUtils.LF) {
    692            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    693                lastIdx--;
    694            }
    695        } else if (last != CharUtils.CR) {
    696            lastIdx++;
    697        }
    698        return str.substring(0, lastIdx);
    699    }
    700
    701    /**
    702     * Removes {@code separator} from the end of
    703     * {@code str} if it's there, otherwise leave it alone.
    704     *
    705     * <p>NOTE: This method changed in version 2.0.
    706     * It now more closely matches Perl chomp.
    707     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
    708     * This method uses {@link String#endsWith(String)}.</p>
    709     *
    710     * <pre>
    711     * StringUtils.chomp(null, *)         = null
    712     * StringUtils.chomp("", *)           = ""
    713     * StringUtils.chomp("foobar", "bar") = "foo"
    714     * StringUtils.chomp("foobar", "baz") = "foobar"
    715     * StringUtils.chomp("foo", "foo")    = ""
    716     * StringUtils.chomp("foo ", "foo")   = "foo "
    717     * StringUtils.chomp(" foo", "foo")   = " "
    718     * StringUtils.chomp("foo", "foooo")  = "foo"
    719     * StringUtils.chomp("foo", "")       = "foo"
    720     * StringUtils.chomp("foo", null)     = "foo"
    721     * </pre>
    722     *
    723     * @param str  the String to chomp from, may be null
    724     * @param separator  separator String, may be null
    725     * @return String without trailing separator, {@code null} if null String input
    726     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
    727     */
    728    @Deprecated
    729    public static String chomp(final String str, final String separator) {
    730        return Strings.CS.removeEnd(str, separator);
    731    }
    732
    733    /**
    734     * Remove the last character from a String.
    735     *
    736     * <p>If the String ends in {@code \r\n}, then remove both
    737     * of them.</p>
    738     *
    739     * <pre>
    740     * StringUtils.chop(null)          = null
    741     * StringUtils.chop("")            = ""
    742     * StringUtils.chop("abc \r")      = "abc "
    743     * StringUtils.chop("abc\n")       = "abc"
    744     * StringUtils.chop("abc\r\n")     = "abc"
    745     * StringUtils.chop("abc")         = "ab"
    746     * StringUtils.chop("abc\nabc")    = "abc\nab"
    747     * StringUtils.chop("a")           = ""
    748     * StringUtils.chop("\r")          = ""
    749     * StringUtils.chop("\n")          = ""
    750     * StringUtils.chop("\r\n")        = ""
    751     * </pre>
    752     *
    753     * @param str  the String to chop last character from, may be null
    754     * @return String without last character, {@code null} if null String input
    755     */
    756    public static String chop(final String str) {
    757        if (str == null) {
    758            return null;
    759        }
    760        final int strLen = str.length();
    761        if (strLen < 2) {
    762            return EMPTY;
    763        }
    764        final int lastIdx = strLen - 1;
    765        final String ret = str.substring(0, lastIdx);
    766        final char last = str.charAt(lastIdx);
    767        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
    768            return ret.substring(0, lastIdx - 1);
    769        }
    770        return ret;
    771    }
    772
    773    /**
    774     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    775     * <ul>
    776     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    777     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    778     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    779     * </ul>
    780     *
    781     * <p>This is a {@code null} safe version of :</p>
    782     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    783     *
    784     * <p>{@code null} value is considered less than non-{@code null} value.
    785     * Two {@code null} references are considered equal.</p>
    786     *
    787     * <pre>{@code
    788     * StringUtils.compare(null, null)   = 0
    789     * StringUtils.compare(null , "a")   < 0
    790     * StringUtils.compare("a", null)   > 0
    791     * StringUtils.compare("abc", "abc") = 0
    792     * StringUtils.compare("a", "b")     < 0
    793     * StringUtils.compare("b", "a")     > 0
    794     * StringUtils.compare("a", "B")     > 0
    795     * StringUtils.compare("ab", "abc")  < 0
    796     * }</pre>
    797     *
    798     * @see #compare(String, String, boolean)
    799     * @see String#compareTo(String)
    800     * @param str1  the String to compare from
    801     * @param str2  the String to compare to
    802     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
    803     * @since 3.5
    804     * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}
    805     */
    806    @Deprecated
    807    public static int compare(final String str1, final String str2) {
    808        return Strings.CS.compare(str1, str2);
    809    }
    810
    811    /**
    812     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    813     * <ul>
    814     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    815     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    816     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    817     * </ul>
    818     *
    819     * <p>This is a {@code null} safe version of :</p>
    820     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    821     *
    822     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    823     * Two {@code null} references are considered equal.</p>
    824     *
    825     * <pre>{@code
    826     * StringUtils.compare(null, null, *)     = 0
    827     * StringUtils.compare(null , "a", true)  < 0
    828     * StringUtils.compare(null , "a", false) > 0
    829     * StringUtils.compare("a", null, true)   > 0
    830     * StringUtils.compare("a", null, false)  < 0
    831     * StringUtils.compare("abc", "abc", *)   = 0
    832     * StringUtils.compare("a", "b", *)       < 0
    833     * StringUtils.compare("b", "a", *)       > 0
    834     * StringUtils.compare("a", "B", *)       > 0
    835     * StringUtils.compare("ab", "abc", *)    < 0
    836     * }</pre>
    837     *
    838     * @see String#compareTo(String)
    839     * @param str1  the String to compare from
    840     * @param str2  the String to compare to
    841     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    842     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
    843     * @since 3.5
    844     */
    845    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
    846        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    847            return 0;
    848        }
    849        if (str1 == null) {
    850            return nullIsLess ? -1 : 1;
    851        }
    852        if (str2 == null) {
    853            return nullIsLess ? 1 : - 1;
    854        }
    855        return str1.compareTo(str2);
    856    }
    857
    858    /**
    859     * Compare two Strings lexicographically, ignoring case differences,
    860     * as per {@link String#compareToIgnoreCase(String)}, returning :
    861     * <ul>
    862     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    863     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    864     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    865     * </ul>
    866     *
    867     * <p>This is a {@code null} safe version of :</p>
    868     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    869     *
    870     * <p>{@code null} value is considered less than non-{@code null} value.
    871     * Two {@code null} references are considered equal.
    872     * Comparison is case insensitive.</p>
    873     *
    874     * <pre>{@code
    875     * StringUtils.compareIgnoreCase(null, null)   = 0
    876     * StringUtils.compareIgnoreCase(null , "a")   < 0
    877     * StringUtils.compareIgnoreCase("a", null)    > 0
    878     * StringUtils.compareIgnoreCase("abc", "abc") = 0
    879     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
    880     * StringUtils.compareIgnoreCase("a", "b")     < 0
    881     * StringUtils.compareIgnoreCase("b", "a")     > 0
    882     * StringUtils.compareIgnoreCase("a", "B")     < 0
    883     * StringUtils.compareIgnoreCase("A", "b")     < 0
    884     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
    885     * }</pre>
    886     *
    887     * @see #compareIgnoreCase(String, String, boolean)
    888     * @see String#compareToIgnoreCase(String)
    889     * @param str1  the String to compare from
    890     * @param str2  the String to compare to
    891     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    892     *          ignoring case differences.
    893     * @since 3.5
    894     * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}
    895     */
    896    @Deprecated
    897    public static int compareIgnoreCase(final String str1, final String str2) {
    898        return Strings.CI.compare(str1, str2);
    899    }
    900
    901    /**
    902     * Compare two Strings lexicographically, ignoring case differences,
    903     * as per {@link String#compareToIgnoreCase(String)}, returning :
    904     * <ul>
    905     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    906     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    907     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    908     * </ul>
    909     *
    910     * <p>This is a {@code null} safe version of :</p>
    911     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    912     *
    913     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    914     * Two {@code null} references are considered equal.
    915     * Comparison is case insensitive.</p>
    916     *
    917     * <pre>{@code
    918     * StringUtils.compareIgnoreCase(null, null, *)     = 0
    919     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
    920     * StringUtils.compareIgnoreCase(null , "a", false) > 0
    921     * StringUtils.compareIgnoreCase("a", null, true)   > 0
    922     * StringUtils.compareIgnoreCase("a", null, false)  < 0
    923     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
    924     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
    925     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
    926     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
    927     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
    928     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
    929     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
    930     * }</pre>
    931     *
    932     * @see String#compareToIgnoreCase(String)
    933     * @param str1  the String to compare from
    934     * @param str2  the String to compare to
    935     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    936     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    937     *          ignoring case differences.
    938     * @since 3.5
    939     */
    940    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
    941        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    942            return 0;
    943        }
    944        if (str1 == null) {
    945            return nullIsLess ? -1 : 1;
    946        }
    947        if (str2 == null) {
    948            return nullIsLess ? 1 : - 1;
    949        }
    950        return str1.compareToIgnoreCase(str2);
    951    }
    952
    953    /**
    954     * Tests if CharSequence contains a search CharSequence, handling {@code null}.
    955     * This method uses {@link String#indexOf(String)} if possible.
    956     *
    957     * <p>A {@code null} CharSequence will return {@code false}.</p>
    958     *
    959     * <pre>
    960     * StringUtils.contains(null, *)     = false
    961     * StringUtils.contains(*, null)     = false
    962     * StringUtils.contains("", "")      = true
    963     * StringUtils.contains("abc", "")   = true
    964     * StringUtils.contains("abc", "a")  = true
    965     * StringUtils.contains("abc", "z")  = false
    966     * </pre>
    967     *
    968     * @param seq  the CharSequence to check, may be null
    969     * @param searchSeq  the CharSequence to find, may be null
    970     * @return true if the CharSequence contains the search CharSequence,
    971     *  false if not or {@code null} string input
    972     * @since 2.0
    973     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
    974     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}
    975     */
    976    @Deprecated
    977    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
    978        return Strings.CS.contains(seq, searchSeq);
    979    }
    980
    981    /**
    982     * Tests if CharSequence contains a search character, handling {@code null}.
    983     * This method uses {@link String#indexOf(int)} if possible.
    984     *
    985     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
    986     *
    987     * <pre>
    988     * StringUtils.contains(null, *)    = false
    989     * StringUtils.contains("", *)      = false
    990     * StringUtils.contains("abc", 'a') = true
    991     * StringUtils.contains("abc", 'z') = false
    992     * </pre>
    993     *
    994     * @param seq  the CharSequence to check, may be null
    995     * @param searchChar  the character to find
    996     * @return true if the CharSequence contains the search character,
    997     *  false if not or {@code null} string input
    998     * @since 2.0
    999     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
    1000     */
    1001    public static boolean contains(final CharSequence seq, final int searchChar) {
    1002        if (isEmpty(seq)) {
    1003            return false;
    1004        }
    1005        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
    1006    }
    1007
    1008    /**
    1009     * Tests if the CharSequence contains any character in the given
    1010     * set of characters.
    1011     *
    1012     * <p>A {@code null} CharSequence will return {@code false}.
    1013     * A {@code null} or zero length search array will return {@code false}.</p>
    1014     *
    1015     * <pre>
    1016     * StringUtils.containsAny(null, *)                  = false
    1017     * StringUtils.containsAny("", *)                    = false
    1018     * StringUtils.containsAny(*, null)                  = false
    1019     * StringUtils.containsAny(*, [])                    = false
    1020     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    1021     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    1022     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    1023     * StringUtils.containsAny("aba", ['z'])             = false
    1024     * </pre>
    1025     *
    1026     * @param cs  the CharSequence to check, may be null
    1027     * @param searchChars  the chars to search for, may be null
    1028     * @return the {@code true} if any of the chars are found,
    1029     * {@code false} if no match or null input
    1030     * @since 2.4
    1031     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
    1032     */
    1033    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    1034        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1035            return false;
    1036        }
    1037        final int csLength = cs.length();
    1038        final int searchLength = searchChars.length;
    1039        final int csLast = csLength - 1;
    1040        final int searchLast = searchLength - 1;
    1041        for (int i = 0; i < csLength; i++) {
    1042            final char ch = cs.charAt(i);
    1043            for (int j = 0; j < searchLength; j++) {
    1044                if (searchChars[j] == ch) {
    1045                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1046                        return true;
    1047                    }
    1048                }
    1049            }
    1050        }
    1051        return false;
    1052    }
    1053
    1054    /**
    1055     * Tests if the CharSequence contains any character in the given set of characters.
    1056     *
    1057     * <p>
    1058     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
    1059     * {@code false}.
    1060     * </p>
    1061     *
    1062     * <pre>
    1063     * StringUtils.containsAny(null, *)               = false
    1064     * StringUtils.containsAny("", *)                 = false
    1065     * StringUtils.containsAny(*, null)               = false
    1066     * StringUtils.containsAny(*, "")                 = false
    1067     * StringUtils.containsAny("zzabyycdxx", "za")    = true
    1068     * StringUtils.containsAny("zzabyycdxx", "by")    = true
    1069     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
    1070     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
    1071     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
    1072     * StringUtils.containsAny("aba", "z")            = false
    1073     * </pre>
    1074     *
    1075     * @param cs
    1076     *            the CharSequence to check, may be null
    1077     * @param searchChars
    1078     *            the chars to search for, may be null
    1079     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
    1080     * @since 2.4
    1081     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
    1082     */
    1083    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
    1084        if (searchChars == null) {
    1085            return false;
    1086        }
    1087        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
    1088    }
    1089
    1090    /**
    1091     * Tests if the CharSequence contains any of the CharSequences in the given array.
    1092     *
    1093     * <p>
    1094     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1095     * return {@code false}.
    1096     * </p>
    1097     *
    1098     * <pre>
    1099     * StringUtils.containsAny(null, *)            = false
    1100     * StringUtils.containsAny("", *)              = false
    1101     * StringUtils.containsAny(*, null)            = false
    1102     * StringUtils.containsAny(*, [])              = false
    1103     * StringUtils.containsAny("abcd", "ab", null) = true
    1104     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1105     * StringUtils.containsAny("abc", "d", "abc")  = true
    1106     * </pre>
    1107     *
    1108     * @param cs The CharSequence to check, may be null
    1109     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1110     *        null as well.
    1111     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1112     * @since 3.4
    1113     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}
    1114     */
    1115    @Deprecated
    1116    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
    1117        return Strings.CS.containsAny(cs, searchCharSequences);
    1118    }
    1119
    1120    /**
    1121     * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
    1122     *
    1123     * <p>
    1124     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1125     * return {@code false}.
    1126     * </p>
    1127     *
    1128     * <pre>
    1129     * StringUtils.containsAny(null, *)            = false
    1130     * StringUtils.containsAny("", *)              = false
    1131     * StringUtils.containsAny(*, null)            = false
    1132     * StringUtils.containsAny(*, [])              = false
    1133     * StringUtils.containsAny("abcd", "ab", null) = true
    1134     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1135     * StringUtils.containsAny("abc", "d", "abc")  = true
    1136     * StringUtils.containsAny("abc", "D", "ABC")  = true
    1137     * StringUtils.containsAny("ABC", "d", "abc")  = true
    1138     * </pre>
    1139     *
    1140     * @param cs The CharSequence to check, may be null
    1141     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1142     *        null as well.
    1143     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1144     * @since 3.12.0
    1145     * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}
    1146     */
    1147    @Deprecated
    1148    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
    1149        return Strings.CI.containsAny(cs, searchCharSequences);
    1150    }
    1151
    1152    /**
    1153     * Tests if CharSequence contains a search CharSequence irrespective of case,
    1154     * handling {@code null}. Case-insensitivity is defined as by
    1155     * {@link String#equalsIgnoreCase(String)}.
    1156     *
    1157     * <p>A {@code null} CharSequence will return {@code false}.
    1158     *
    1159     * <pre>
    1160     * StringUtils.containsIgnoreCase(null, *)    = false
    1161     * StringUtils.containsIgnoreCase(*, null)    = false
    1162     * StringUtils.containsIgnoreCase("", "")     = true
    1163     * StringUtils.containsIgnoreCase("abc", "")  = true
    1164     * StringUtils.containsIgnoreCase("abc", "a") = true
    1165     * StringUtils.containsIgnoreCase("abc", "z") = false
    1166     * StringUtils.containsIgnoreCase("abc", "A") = true
    1167     * StringUtils.containsIgnoreCase("abc", "Z") = false
    1168     * </pre>
    1169     *
    1170     * @param str  the CharSequence to check, may be null
    1171     * @param searchStr  the CharSequence to find, may be null
    1172     * @return true if the CharSequence contains the search CharSequence irrespective of
    1173     * case or false if not or {@code null} string input
    1174     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
    1175     * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}
    1176     */
    1177    @Deprecated
    1178    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1179        return Strings.CI.contains(str, searchStr);
    1180    }
    1181
    1182    /**
    1183     * Tests that the CharSequence does not contain certain characters.
    1184     *
    1185     * <p>A {@code null} CharSequence will return {@code true}.
    1186     * A {@code null} invalid character array will return {@code true}.
    1187     * An empty CharSequence (length()=0) always returns true.</p>
    1188     *
    1189     * <pre>
    1190     * StringUtils.containsNone(null, *)       = true
    1191     * StringUtils.containsNone(*, null)       = true
    1192     * StringUtils.containsNone("", *)         = true
    1193     * StringUtils.containsNone("ab", '')      = true
    1194     * StringUtils.containsNone("abab", 'xyz') = true
    1195     * StringUtils.containsNone("ab1", 'xyz')  = true
    1196     * StringUtils.containsNone("abz", 'xyz')  = false
    1197     * </pre>
    1198     *
    1199     * @param cs  the CharSequence to check, may be null
    1200     * @param searchChars  an array of invalid chars, may be null
    1201     * @return true if it contains none of the invalid chars, or is null
    1202     * @since 2.0
    1203     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
    1204     */
    1205    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    1206        if (cs == null || searchChars == null) {
    1207            return true;
    1208        }
    1209        final int csLen = cs.length();
    1210        final int csLast = csLen - 1;
    1211        final int searchLen = searchChars.length;
    1212        final int searchLast = searchLen - 1;
    1213        for (int i = 0; i < csLen; i++) {
    1214            final char ch = cs.charAt(i);
    1215            for (int j = 0; j < searchLen; j++) {
    1216                if (searchChars[j] == ch) {
    1217                    if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1218                        return false;
    1219                    }
    1220                }
    1221            }
    1222        }
    1223        return true;
    1224    }
    1225
    1226    /**
    1227     * Tests that the CharSequence does not contain certain characters.
    1228     *
    1229     * <p>A {@code null} CharSequence will return {@code true}.
    1230     * A {@code null} invalid character array will return {@code true}.
    1231     * An empty String ("") always returns true.</p>
    1232     *
    1233     * <pre>
    1234     * StringUtils.containsNone(null, *)       = true
    1235     * StringUtils.containsNone(*, null)       = true
    1236     * StringUtils.containsNone("", *)         = true
    1237     * StringUtils.containsNone("ab", "")      = true
    1238     * StringUtils.containsNone("abab", "xyz") = true
    1239     * StringUtils.containsNone("ab1", "xyz")  = true
    1240     * StringUtils.containsNone("abz", "xyz")  = false
    1241     * </pre>
    1242     *
    1243     * @param cs  the CharSequence to check, may be null
    1244     * @param invalidChars  a String of invalid chars, may be null
    1245     * @return true if it contains none of the invalid chars, or is null
    1246     * @since 2.0
    1247     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    1248     */
    1249    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
    1250        if (invalidChars == null) {
    1251            return true;
    1252        }
    1253        return containsNone(cs, invalidChars.toCharArray());
    1254    }
    1255
    1256    /**
    1257     * Tests if the CharSequence contains only certain characters.
    1258     *
    1259     * <p>A {@code null} CharSequence will return {@code false}.
    1260     * A {@code null} valid character array will return {@code false}.
    1261     * An empty CharSequence (length()=0) always returns {@code true}.</p>
    1262     *
    1263     * <pre>
    1264     * StringUtils.containsOnly(null, *)       = false
    1265     * StringUtils.containsOnly(*, null)       = false
    1266     * StringUtils.containsOnly("", *)         = true
    1267     * StringUtils.containsOnly("ab", '')      = false
    1268     * StringUtils.containsOnly("abab", 'abc') = true
    1269     * StringUtils.containsOnly("ab1", 'abc')  = false
    1270     * StringUtils.containsOnly("abz", 'abc')  = false
    1271     * </pre>
    1272     *
    1273     * @param cs  the String to check, may be null
    1274     * @param valid  an array of valid chars, may be null
    1275     * @return true if it only contains valid chars and is non-null
    1276     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
    1277     */
    1278    public static boolean containsOnly(final CharSequence cs, final char... valid) {
    1279        // All these pre-checks are to maintain API with an older version
    1280        if (valid == null || cs == null) {
    1281            return false;
    1282        }
    1283        if (cs.length() == 0) {
    1284            return true;
    1285        }
    1286        if (valid.length == 0) {
    1287            return false;
    1288        }
    1289        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    1290    }
    1291
    1292    /**
    1293     * Tests if the CharSequence contains only certain characters.
    1294     *
    1295     * <p>A {@code null} CharSequence will return {@code false}.
    1296     * A {@code null} valid character String will return {@code false}.
    1297     * An empty String (length()=0) always returns {@code true}.</p>
    1298     *
    1299     * <pre>
    1300     * StringUtils.containsOnly(null, *)       = false
    1301     * StringUtils.containsOnly(*, null)       = false
    1302     * StringUtils.containsOnly("", *)         = true
    1303     * StringUtils.containsOnly("ab", "")      = false
    1304     * StringUtils.containsOnly("abab", "abc") = true
    1305     * StringUtils.containsOnly("ab1", "abc")  = false
    1306     * StringUtils.containsOnly("abz", "abc")  = false
    1307     * </pre>
    1308     *
    1309     * @param cs  the CharSequence to check, may be null
    1310     * @param validChars  a String of valid chars, may be null
    1311     * @return true if it only contains valid chars and is non-null
    1312     * @since 2.0
    1313     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    1314     */
    1315    public static boolean containsOnly(final CharSequence cs, final String validChars) {
    1316        if (cs == null || validChars == null) {
    1317            return false;
    1318        }
    1319        return containsOnly(cs, validChars.toCharArray());
    1320    }
    1321
    1322    /**
    1323     * Tests whether the given CharSequence contains any whitespace characters.
    1324     *
    1325     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1326     *
    1327     * <pre>
    1328     * StringUtils.containsWhitespace(null)       = false
    1329     * StringUtils.containsWhitespace("")         = false
    1330     * StringUtils.containsWhitespace("ab")       = false
    1331     * StringUtils.containsWhitespace(" ab")      = true
    1332     * StringUtils.containsWhitespace("a b")      = true
    1333     * StringUtils.containsWhitespace("ab ")      = true
    1334     * </pre>
    1335     *
    1336     * @param seq the CharSequence to check (may be {@code null})
    1337     * @return {@code true} if the CharSequence is not empty and
    1338     * contains at least 1 (breaking) whitespace character
    1339     * @since 3.0
    1340     */
    1341    // From org.springframework.util.StringUtils, under Apache License 2.0
    1342    public static boolean containsWhitespace(final CharSequence seq) {
    1343        if (isEmpty(seq)) {
    1344            return false;
    1345        }
    1346        final int strLen = seq.length();
    1347        for (int i = 0; i < strLen; i++) {
    1348            if (Character.isWhitespace(seq.charAt(i))) {
    1349                return true;
    1350            }
    1351        }
    1352        return false;
    1353    }
    1354
    1355    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
    1356        for (int i = 0; i < decomposed.length(); i++) {
    1357            final char charAt = decomposed.charAt(i);
    1358            switch (charAt) {
    1359            case '\u0141':
    1360                decomposed.setCharAt(i, 'L');
    1361                break;
    1362            case '\u0142':
    1363                decomposed.setCharAt(i, 'l');
    1364                break;
    1365            // D with stroke
    1366            case '\u0110':
    1367                // LATIN CAPITAL LETTER D WITH STROKE
    1368                decomposed.setCharAt(i, 'D');
    1369                break;
    1370            case '\u0111':
    1371                // LATIN SMALL LETTER D WITH STROKE
    1372                decomposed.setCharAt(i, 'd');
    1373                break;
    1374            // I with bar
    1375            case '\u0197':
    1376                decomposed.setCharAt(i, 'I');
    1377                break;
    1378            case '\u0268':
    1379                decomposed.setCharAt(i, 'i');
    1380                break;
    1381            case '\u1D7B':
    1382                decomposed.setCharAt(i, 'I');
    1383                break;
    1384            case '\u1DA4':
    1385                decomposed.setCharAt(i, 'i');
    1386                break;
    1387            case '\u1DA7':
    1388                decomposed.setCharAt(i, 'I');
    1389                break;
    1390            // U with bar
    1391            case '\u0244':
    1392                // LATIN CAPITAL LETTER U BAR
    1393                decomposed.setCharAt(i, 'U');
    1394                break;
    1395            case '\u0289':
    1396                // LATIN SMALL LETTER U BAR
    1397                decomposed.setCharAt(i, 'u');
    1398                break;
    1399            case '\u1D7E':
    1400                // LATIN SMALL CAPITAL LETTER U WITH STROKE
    1401                decomposed.setCharAt(i, 'U');
    1402                break;
    1403            case '\u1DB6':
    1404                // MODIFIER LETTER SMALL U BAR
    1405                decomposed.setCharAt(i, 'u');
    1406                break;
    1407            // T with stroke
    1408            case '\u0166':
    1409                // LATIN CAPITAL LETTER T WITH STROKE
    1410                decomposed.setCharAt(i, 'T');
    1411                break;
    1412            case '\u0167':
    1413                // LATIN SMALL LETTER T WITH STROKE
    1414                decomposed.setCharAt(i, 't');
    1415                break;
    1416            default:
    1417                break;
    1418            }
    1419        }
    1420    }
    1421
    1422    /**
    1423     * Counts how many times the char appears in the given string.
    1424     *
    1425     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1426     *
    1427     * <pre>
    1428     * StringUtils.countMatches(null, *)     = 0
    1429     * StringUtils.countMatches("", *)       = 0
    1430     * StringUtils.countMatches("abba", 0)   = 0
    1431     * StringUtils.countMatches("abba", 'a') = 2
    1432     * StringUtils.countMatches("abba", 'b') = 2
    1433     * StringUtils.countMatches("abba", 'x') = 0
    1434     * </pre>
    1435     *
    1436     * @param str  the CharSequence to check, may be null
    1437     * @param ch  the char to count
    1438     * @return the number of occurrences, 0 if the CharSequence is {@code null}
    1439     * @since 3.4
    1440     */
    1441    public static int countMatches(final CharSequence str, final char ch) {
    1442        if (isEmpty(str)) {
    1443            return 0;
    1444        }
    1445        int count = 0;
    1446        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
    1447        for (int i = 0; i < str.length(); i++) {
    1448            if (ch == str.charAt(i)) {
    1449                count++;
    1450            }
    1451        }
    1452        return count;
    1453    }
    1454
    1455    /**
    1456     * Counts how many times the substring appears in the larger string.
    1457     * Note that the code only counts non-overlapping matches.
    1458     *
    1459     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1460     *
    1461     * <pre>
    1462     * StringUtils.countMatches(null, *)        = 0
    1463     * StringUtils.countMatches("", *)          = 0
    1464     * StringUtils.countMatches("abba", null)   = 0
    1465     * StringUtils.countMatches("abba", "")     = 0
    1466     * StringUtils.countMatches("abba", "a")    = 2
    1467     * StringUtils.countMatches("abba", "ab")   = 1
    1468     * StringUtils.countMatches("abba", "xxx")  = 0
    1469     * StringUtils.countMatches("ababa", "aba") = 1
    1470     * </pre>
    1471     *
    1472     * @param str  the CharSequence to check, may be null
    1473     * @param sub  the substring to count, may be null
    1474     * @return the number of occurrences, 0 if either CharSequence is {@code null}
    1475     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
    1476     */
    1477    public static int countMatches(final CharSequence str, final CharSequence sub) {
    1478        if (isEmpty(str) || isEmpty(sub)) {
    1479            return 0;
    1480        }
    1481        int count = 0;
    1482        int idx = 0;
    1483        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
    1484            count++;
    1485            idx += sub.length();
    1486        }
    1487        return count;
    1488    }
    1489
    1490    /**
    1491     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
    1492     * {@code null}), the value of {@code defaultStr}.
    1493     *
    1494     * <p>
    1495     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    1496     * </p>
    1497     *
    1498     * <pre>
    1499     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
    1500     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
    1501     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
    1502     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
    1503     * StringUtils.defaultIfBlank("", null)      = null
    1504     * </pre>
    1505     *
    1506     * @param <T>        the specific kind of CharSequence
    1507     * @param str        the CharSequence to check, may be null
    1508     * @param defaultStr the default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code""}) or
    1509     *                   {@code null}); may be null
    1510     * @return the passed in CharSequence, or the default
    1511     * @see StringUtils#defaultString(String, String)
    1512     * @see #isBlank(CharSequence)
    1513     */
    1514    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
    1515        return isBlank(str) ? defaultStr : str;
    1516    }
    1517
    1518    /**
    1519     * Returns either the passed in CharSequence, or if the CharSequence is
    1520     * empty or {@code null}, the value of {@code defaultStr}.
    1521     *
    1522     * <pre>
    1523     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    1524     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    1525     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
    1526     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    1527     * StringUtils.defaultIfEmpty("", null)      = null
    1528     * </pre>
    1529     * @param <T> the specific kind of CharSequence
    1530     * @param str  the CharSequence to check, may be null
    1531     * @param defaultStr  the default CharSequence to return
    1532     *  if the input is empty ("") or {@code null}, may be null
    1533     * @return the passed in CharSequence, or the default
    1534     * @see StringUtils#defaultString(String, String)
    1535     */
    1536    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
    1537        return isEmpty(str) ? defaultStr : str;
    1538    }
    1539
    1540    /**
    1541     * Returns either the passed in String,
    1542     * or if the String is {@code null}, an empty String ("").
    1543     *
    1544     * <pre>
    1545     * StringUtils.defaultString(null)  = ""
    1546     * StringUtils.defaultString("")    = ""
    1547     * StringUtils.defaultString("bat") = "bat"
    1548     * </pre>
    1549     *
    1550     * @see Objects#toString(Object, String)
    1551     * @see String#valueOf(Object)
    1552     * @param str  the String to check, may be null
    1553     * @return the passed in String, or the empty String if it
    1554     *  was {@code null}
    1555     */
    1556    public static String defaultString(final String str) {
    1557        return Objects.toString(str, EMPTY);
    1558    }
    1559
    1560    /**
    1561     * Returns either the given String, or if the String is
    1562     * {@code null}, {@code nullDefault}.
    1563     *
    1564     * <pre>
    1565     * StringUtils.defaultString(null, "NULL")  = "NULL"
    1566     * StringUtils.defaultString("", "NULL")    = ""
    1567     * StringUtils.defaultString("bat", "NULL") = "bat"
    1568     * </pre>
    1569     * <p>
    1570     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
    1571     * </p>
    1572     * <pre>
    1573     * Objects.toString(null, "NULL")  = "NULL"
    1574     * Objects.toString("", "NULL")    = ""
    1575     * Objects.toString("bat", "NULL") = "bat"
    1576     * </pre>
    1577     *
    1578     * @see Objects#toString(Object, String)
    1579     * @see String#valueOf(Object)
    1580     * @param str  the String to check, may be null
    1581     * @param nullDefault  the default String to return
    1582     *  if the input is {@code null}, may be null
    1583     * @return the passed in String, or the default if it was {@code null}
    1584     * @deprecated Use {@link Objects#toString(Object, String)}
    1585     */
    1586    @Deprecated
    1587    public static String defaultString(final String str, final String nullDefault) {
    1588        return Objects.toString(str, nullDefault);
    1589    }
    1590
    1591    /**
    1592     * Deletes all whitespaces from a String as defined by
    1593     * {@link Character#isWhitespace(char)}.
    1594     *
    1595     * <pre>
    1596     * StringUtils.deleteWhitespace(null)         = null
    1597     * StringUtils.deleteWhitespace("")           = ""
    1598     * StringUtils.deleteWhitespace("abc")        = "abc"
    1599     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    1600     * </pre>
    1601     *
    1602     * @param str  the String to delete whitespace from, may be null
    1603     * @return the String without whitespaces, {@code null} if null String input
    1604     */
    1605    public static String deleteWhitespace(final String str) {
    1606        if (isEmpty(str)) {
    1607            return str;
    1608        }
    1609        final int sz = str.length();
    1610        final char[] chs = new char[sz];
    1611        int count = 0;
    1612        for (int i = 0; i < sz; i++) {
    1613            if (!Character.isWhitespace(str.charAt(i))) {
    1614                chs[count++] = str.charAt(i);
    1615            }
    1616        }
    1617        if (count == sz) {
    1618            return str;
    1619        }
    1620        if (count == 0) {
    1621            return EMPTY;
    1622        }
    1623        return new String(chs, 0, count);
    1624    }
    1625
    1626    /**
    1627     * Compares two Strings, and returns the portion where they differ.
    1628     * More precisely, return the remainder of the second String,
    1629     * starting from where it's different from the first. This means that
    1630     * the difference between "abc" and "ab" is the empty String and not "c".
    1631     *
    1632     * <p>For example,
    1633     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
    1634     *
    1635     * <pre>
    1636     * StringUtils.difference(null, null)       = null
    1637     * StringUtils.difference("", "")           = ""
    1638     * StringUtils.difference("", "abc")        = "abc"
    1639     * StringUtils.difference("abc", "")        = ""
    1640     * StringUtils.difference("abc", "abc")     = ""
    1641     * StringUtils.difference("abc", "ab")      = ""
    1642     * StringUtils.difference("ab", "abxyz")    = "xyz"
    1643     * StringUtils.difference("abcde", "abxyz") = "xyz"
    1644     * StringUtils.difference("abcde", "xyz")   = "xyz"
    1645     * </pre>
    1646     *
    1647     * @param str1  the first String, may be null
    1648     * @param str2  the second String, may be null
    1649     * @return the portion of str2 where it differs from str1; returns the
    1650     * empty String if they are equal
    1651     * @see #indexOfDifference(CharSequence,CharSequence)
    1652     * @since 2.0
    1653     */
    1654    public static String difference(final String str1, final String str2) {
    1655        if (str1 == null) {
    1656            return str2;
    1657        }
    1658        if (str2 == null) {
    1659            return str1;
    1660        }
    1661        final int at = indexOfDifference(str1, str2);
    1662        if (at == INDEX_NOT_FOUND) {
    1663            return EMPTY;
    1664        }
    1665        return str2.substring(at);
    1666    }
    1667
    1668    /**
    1669     * Tests if a CharSequence ends with a specified suffix.
    1670     *
    1671     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1672     * references are considered to be equal. The comparison is case-sensitive.</p>
    1673     *
    1674     * <pre>
    1675     * StringUtils.endsWith(null, null)      = true
    1676     * StringUtils.endsWith(null, "def")     = false
    1677     * StringUtils.endsWith("abcdef", null)  = false
    1678     * StringUtils.endsWith("abcdef", "def") = true
    1679     * StringUtils.endsWith("ABCDEF", "def") = false
    1680     * StringUtils.endsWith("ABCDEF", "cde") = false
    1681     * StringUtils.endsWith("ABCDEF", "")    = true
    1682     * </pre>
    1683     *
    1684     * @see String#endsWith(String)
    1685     * @param str  the CharSequence to check, may be null
    1686     * @param suffix the suffix to find, may be null
    1687     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
    1688     *  both {@code null}
    1689     * @since 2.4
    1690     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
    1691     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
    1692     */
    1693    @Deprecated
    1694    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
    1695        return Strings.CS.endsWith(str, suffix);
    1696    }
    1697
    1698    /**
    1699     * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
    1700     *
    1701     * <pre>
    1702     * StringUtils.endsWithAny(null, null)                  = false
    1703     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
    1704     * StringUtils.endsWithAny("abcxyz", null)              = false
    1705     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
    1706     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
    1707     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    1708     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
    1709     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
    1710     * </pre>
    1711     *
    1712     * @param sequence  the CharSequence to check, may be null
    1713     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
    1714     * @see StringUtils#endsWith(CharSequence, CharSequence)
    1715     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    1716     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
    1717     * @since 3.0
    1718     * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}
    1719     */
    1720    @Deprecated
    1721    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    1722        return Strings.CS.endsWithAny(sequence, searchStrings);
    1723    }
    1724
    1725    /**
    1726     * Case-insensitive check if a CharSequence ends with a specified suffix.
    1727     *
    1728     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1729     * references are considered to be equal. The comparison is case insensitive.</p>
    1730     *
    1731     * <pre>
    1732     * StringUtils.endsWithIgnoreCase(null, null)      = true
    1733     * StringUtils.endsWithIgnoreCase(null, "def")     = false
    1734     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    1735     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    1736     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    1737     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    1738     * </pre>
    1739     *
    1740     * @see String#endsWith(String)
    1741     * @param str  the CharSequence to check, may be null
    1742     * @param suffix the suffix to find, may be null
    1743     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
    1744     *  both {@code null}
    1745     * @since 2.4
    1746     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
    1747     * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
    1748     */
    1749    @Deprecated
    1750    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
    1751        return Strings.CI.endsWith(str, suffix);
    1752    }
    1753
    1754    /**
    1755     * Compares two CharSequences, returning {@code true} if they represent
    1756     * equal sequences of characters.
    1757     *
    1758     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1759     * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
    1760     *
    1761     * <pre>
    1762     * StringUtils.equals(null, null)   = true
    1763     * StringUtils.equals(null, "abc")  = false
    1764     * StringUtils.equals("abc", null)  = false
    1765     * StringUtils.equals("abc", "abc") = true
    1766     * StringUtils.equals("abc", "ABC") = false
    1767     * </pre>
    1768     *
    1769     * @param cs1  the first CharSequence, may be {@code null}
    1770     * @param cs2  the second CharSequence, may be {@code null}
    1771     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
    1772     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    1773     * @see Object#equals(Object)
    1774     * @see #equalsIgnoreCase(CharSequence, CharSequence)
    1775     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}
    1776     */
    1777    @Deprecated
    1778    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
    1779        return Strings.CS.equals(cs1, cs2);
    1780    }
    1781
    1782    /**
    1783     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1784     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
    1785     *
    1786     * <pre>
    1787     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
    1788     * StringUtils.equalsAny(null, null, null)    = true
    1789     * StringUtils.equalsAny(null, "abc", "def")  = false
    1790     * StringUtils.equalsAny("abc", null, "def")  = false
    1791     * StringUtils.equalsAny("abc", "abc", "def") = true
    1792     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
    1793     * </pre>
    1794     *
    1795     * @param string to compare, may be {@code null}.
    1796     * @param searchStrings a vararg of strings, may be {@code null}.
    1797     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
    1798     * {@code false} if {@code searchStrings} is null or contains no matches.
    1799     * @since 3.5
    1800     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}
    1801     */
    1802    @Deprecated
    1803    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
    1804        return Strings.CS.equalsAny(string, searchStrings);
    1805    }
    1806
    1807    /**
    1808     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1809     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
    1810     *
    1811     * <pre>
    1812     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
    1813     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
    1814     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
    1815     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
    1816     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
    1817     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
    1818     * </pre>
    1819     *
    1820     * @param string to compare, may be {@code null}.
    1821     * @param searchStrings a vararg of strings, may be {@code null}.
    1822     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
    1823     * {@code false} if {@code searchStrings} is null or contains no matches.
    1824     * @since 3.5
    1825     * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI-.equalsAny(CharSequence, CharSequence...)}
    1826     */
    1827    @Deprecated
    1828    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
    1829        return Strings.CI.equalsAny(string, searchStrings);
    1830    }
    1831
    1832    /**
    1833     * Compares two CharSequences, returning {@code true} if they represent
    1834     * equal sequences of characters, ignoring case.
    1835     *
    1836     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1837     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
    1838     *
    1839     * <pre>
    1840     * StringUtils.equalsIgnoreCase(null, null)   = true
    1841     * StringUtils.equalsIgnoreCase(null, "abc")  = false
    1842     * StringUtils.equalsIgnoreCase("abc", null)  = false
    1843     * StringUtils.equalsIgnoreCase("abc", "abc") = true
    1844     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    1845     * </pre>
    1846     *
    1847     * @param cs1  the first CharSequence, may be {@code null}
    1848     * @param cs2  the second CharSequence, may be {@code null}
    1849     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
    1850     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
    1851     * @see #equals(CharSequence, CharSequence)
    1852     * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}
    1853     */
    1854    @Deprecated
    1855    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
    1856        return Strings.CI.equals(cs1, cs2);
    1857    }
    1858
    1859    /**
    1860     * Returns the first value in the array which is not empty (""),
    1861     * {@code null} or whitespace only.
    1862     *
    1863     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1864     *
    1865     * <p>If all values are blank or the array is {@code null}
    1866     * or empty then {@code null} is returned.</p>
    1867     *
    1868     * <pre>
    1869     * StringUtils.firstNonBlank(null, null, null)     = null
    1870     * StringUtils.firstNonBlank(null, "", " ")        = null
    1871     * StringUtils.firstNonBlank("abc")                = "abc"
    1872     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
    1873     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
    1874     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
    1875     * StringUtils.firstNonBlank()                     = null
    1876     * </pre>
    1877     *
    1878     * @param <T> the specific kind of CharSequence
    1879     * @param values  the values to test, may be {@code null} or empty
    1880     * @return the first value from {@code values} which is not blank,
    1881     *  or {@code null} if there are no non-blank values
    1882     * @since 3.8
    1883     */
    1884    @SafeVarargs
    1885    public static <T extends CharSequence> T firstNonBlank(final T... values) {
    1886        if (values != null) {
    1887            for (final T val : values) {
    1888                if (isNotBlank(val)) {
    1889                    return val;
    1890                }
    1891            }
    1892        }
    1893        return null;
    1894    }
    1895
    1896    /**
    1897     * Returns the first value in the array which is not empty.
    1898     *
    1899     * <p>If all values are empty or the array is {@code null}
    1900     * or empty then {@code null} is returned.</p>
    1901     *
    1902     * <pre>
    1903     * StringUtils.firstNonEmpty(null, null, null)   = null
    1904     * StringUtils.firstNonEmpty(null, null, "")     = null
    1905     * StringUtils.firstNonEmpty(null, "", " ")      = " "
    1906     * StringUtils.firstNonEmpty("abc")              = "abc"
    1907     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
    1908     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
    1909     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
    1910     * StringUtils.firstNonEmpty()                   = null
    1911     * </pre>
    1912     *
    1913     * @param <T> the specific kind of CharSequence
    1914     * @param values  the values to test, may be {@code null} or empty
    1915     * @return the first value from {@code values} which is not empty,
    1916     *  or {@code null} if there are no non-empty values
    1917     * @since 3.8
    1918     */
    1919    @SafeVarargs
    1920    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
    1921        if (values != null) {
    1922            for (final T val : values) {
    1923                if (isNotEmpty(val)) {
    1924                    return val;
    1925                }
    1926            }
    1927        }
    1928        return null;
    1929    }
    1930
    1931    /**
    1932     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
    1933     *
    1934     * @param string input string
    1935     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
    1936     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
    1937     * @see String#getBytes(Charset)
    1938     * @since 3.10
    1939     */
    1940    public static byte[] getBytes(final String string, final Charset charset) {
    1941        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
    1942    }
    1943
    1944    /**
    1945     * Calls {@link String#getBytes(String)} in a null-safe manner.
    1946     *
    1947     * @param string input string
    1948     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
    1949     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
    1950     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
    1951     * @see String#getBytes(String)
    1952     * @since 3.10
    1953     */
    1954    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
    1955        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
    1956    }
    1957
    1958    /**
    1959     * Compares all Strings in an array and returns the initial sequence of
    1960     * characters that is common to all of them.
    1961     *
    1962     * <p>For example,
    1963     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
    1964     *
    1965     * <pre>
    1966     * StringUtils.getCommonPrefix(null)                             = ""
    1967     * StringUtils.getCommonPrefix(new String[] {})                  = ""
    1968     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
    1969     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
    1970     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
    1971     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
    1972     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    1973     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    1974     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
    1975     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
    1976     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
    1977     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
    1978     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
    1979     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
    1980     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
    1981     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
    1982     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    1983     * </pre>
    1984     *
    1985     * @param strs  array of String objects, entries may be null
    1986     * @return the initial sequence of characters that are common to all Strings
    1987     * in the array; empty String if the array is null, the elements are all null
    1988     * or if there is no common prefix.
    1989     * @since 2.4
    1990     */
    1991    public static String getCommonPrefix(final String... strs) {
    1992        if (ArrayUtils.isEmpty(strs)) {
    1993            return EMPTY;
    1994        }
    1995        final int smallestIndexOfDiff = indexOfDifference(strs);
    1996        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    1997            // all strings were identical
    1998            if (strs[0] == null) {
    1999                return EMPTY;
    2000            }
    2001            return strs[0];
    2002        }
    2003        if (smallestIndexOfDiff == 0) {
    2004            // there were no common initial characters
    2005            return EMPTY;
    2006        }
    2007        // we found a common initial character sequence
    2008        return strs[0].substring(0, smallestIndexOfDiff);
    2009    }
    2010
    2011    /**
    2012     * Checks if a String {@code str} contains Unicode digits,
    2013     * if yes then concatenate all the digits in {@code str} and return it as a String.
    2014     *
    2015     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
    2016     *
    2017     * <pre>
    2018     * StringUtils.getDigits(null)                 = null
    2019     * StringUtils.getDigits("")                   = ""
    2020     * StringUtils.getDigits("abc")                = ""
    2021     * StringUtils.getDigits("1000$")              = "1000"
    2022     * StringUtils.getDigits("1123~45")            = "112345"
    2023     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
    2024     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
    2025     * </pre>
    2026     *
    2027     * @param str the String to extract digits from, may be null
    2028     * @return String with only digits,
    2029     *           or an empty ("") String if no digits found,
    2030     *           or {@code null} String if {@code str} is null
    2031     * @since 3.6
    2032     */
    2033    public static String getDigits(final String str) {
    2034        if (isEmpty(str)) {
    2035            return str;
    2036        }
    2037        final int sz = str.length();
    2038        final StringBuilder strDigits = new StringBuilder(sz);
    2039        for (int i = 0; i < sz; i++) {
    2040            final char tempChar = str.charAt(i);
    2041            if (Character.isDigit(tempChar)) {
    2042                strDigits.append(tempChar);
    2043            }
    2044        }
    2045        return strDigits.toString();
    2046    }
    2047
    2048    /**
    2049     * Find the Fuzzy Distance which indicates the similarity score between two Strings.
    2050     *
    2051     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
    2052     * TextMate, Atom and others. One point is given for every matched character. Subsequent
    2053     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
    2054     *
    2055     * <pre>
    2056     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
    2057     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
    2058     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
    2059     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
    2060     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
    2061     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
    2062     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
    2063     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
    2064     * </pre>
    2065     *
    2066     * @param term a full term that should be matched against, must not be null
    2067     * @param query the query that will be matched against a term, must not be null
    2068     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
    2069     *  both Strings to lower case.
    2070     * @return result score
    2071     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
    2072     * @since 3.4
    2073     * @deprecated As of 3.6, use Apache Commons Text
    2074     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
    2075     * FuzzyScore</a> instead
    2076     */
    2077    @Deprecated
    2078    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
    2079        if (term == null || query == null) {
    2080            throw new IllegalArgumentException("Strings must not be null");
    2081        }
    2082        if (locale == null) {
    2083            throw new IllegalArgumentException("Locale must not be null");
    2084        }
    2085
    2086        // fuzzy logic is case-insensitive. We normalize the Strings to lower
    2087        // case right from the start. Turning characters to lower case
    2088        // via Character.toLowerCase(char) is unfortunately insufficient
    2089        // as it does not accept a locale.
    2090        final String termLowerCase = term.toString().toLowerCase(locale);
    2091        final String queryLowerCase = query.toString().toLowerCase(locale);
    2092
    2093        // the resulting score
    2094        int score = 0;
    2095
    2096        // the position in the term which will be scanned next for potential
    2097        // query character matches
    2098        int termIndex = 0;
    2099
    2100        // index of the previously matched character in the term
    2101        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
    2102
    2103        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
    2104            final char queryChar = queryLowerCase.charAt(queryIndex);
    2105
    2106            boolean termCharacterMatchFound = false;
    2107            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
    2108                final char termChar = termLowerCase.charAt(termIndex);
    2109
    2110                if (queryChar == termChar) {
    2111                    // simple character matches result in one point
    2112                    score++;
    2113
    2114                    // subsequent character matches further improve
    2115                    // the score.
    2116                    if (previousMatchingCharacterIndex + 1 == termIndex) {
    2117                        score += 2;
    2118                    }
    2119
    2120                    previousMatchingCharacterIndex = termIndex;
    2121
    2122                    // we can leave the nested loop. Every character in the
    2123                    // query can match at most one character in the term.
    2124                    termCharacterMatchFound = true;
    2125                }
    2126            }
    2127        }
    2128
    2129        return score;
    2130    }
    2131
    2132    /**
    2133     * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
    2134     * {@code null}), the value supplied by {@code defaultStrSupplier}.
    2135     *
    2136     * <p>
    2137     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    2138     * </p>
    2139     *
    2140     * <p>
    2141     * Caller responsible for thread-safety and exception handling of default value supplier
    2142     * </p>
    2143     *
    2144     * <pre>
    2145     * {@code
    2146     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
    2147     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
    2148     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
    2149     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
    2150     * StringUtils.getIfBlank("", () -> null)       = null
    2151     * StringUtils.getIfBlank("", null)             = null
    2152     * }</pre>
    2153     *
    2154     * @param <T>             the specific kind of CharSequence
    2155     * @param str             the CharSequence to check, may be null
    2156     * @param defaultSupplier the supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
    2157     *                        ({@code ""}) or {@code null}); may be null
    2158     * @return the passed in CharSequence, or the default
    2159     * @see StringUtils#defaultString(String, String)
    2160     * @see #isBlank(CharSequence)
    2161     * @since 3.10
    2162     */
    2163    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
    2164        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
    2165    }
    2166
    2167    /**
    2168     * Returns either the passed in CharSequence, or if the CharSequence is
    2169     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
    2170     *
    2171     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2172     *
    2173     * <pre>
    2174     * {@code
    2175     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
    2176     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
    2177     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
    2178     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
    2179     * StringUtils.getIfEmpty("", () -> null)        = null
    2180     * StringUtils.getIfEmpty("", null)              = null
    2181     * }
    2182     * </pre>
    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
    2186     *  if the input is empty ("") or {@code null}, may be null
    2187     * @return the passed in CharSequence, or the default
    2188     * @see StringUtils#defaultString(String, String)
    2189     * @since 3.10
    2190     */
    2191    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
    2192        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
    2193    }
    2194
    2195    /**
    2196     * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
    2197     *
    2198     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
    2199     * Winkler increased this measure for matching initial characters.</p>
    2200     *
    2201     * <p>This implementation is based on the Jaro Winkler similarity algorithm
    2202     * from <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
    2203     *
    2204     * <pre>
    2205     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
    2206     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
    2207     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
    2208     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
    2209     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
    2210     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
    2211     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
    2212     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
    2213     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
    2214     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
    2215     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
    2216     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
    2217     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
    2218     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
    2219     * </pre>
    2220     *
    2221     * @param first the first String, must not be null
    2222     * @param second the second String, must not be null
    2223     * @return result distance
    2224     * @throws IllegalArgumentException if either String input {@code null}
    2225     * @since 3.3
    2226     * @deprecated As of 3.6, use Apache Commons Text
    2227     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
    2228     * JaroWinklerDistance</a> instead
    2229     */
    2230    @Deprecated
    2231    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
    2232        final double DEFAULT_SCALING_FACTOR = 0.1;
    2233
    2234        if (first == null || second == null) {
    2235            throw new IllegalArgumentException("Strings must not be null");
    2236        }
    2237
    2238        final int[] mtp = matches(first, second);
    2239        final double m = mtp[0];
    2240        if (m == 0) {
    2241            return 0D;
    2242        }
    2243        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
    2244        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
    2245        return Math.round(jw * 100.0D) / 100.0D;
    2246    }
    2247
    2248    /**
    2249     * Find the Levenshtein distance between two Strings.
    2250     *
    2251     * <p>This is the number of changes needed to change one String into
    2252     * another, where each change is a single character modification (deletion,
    2253     * insertion or substitution).</p>
    2254     *
    2255     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
    2256     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
    2257     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
    2258     *
    2259     * <pre>
    2260     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    2261     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    2262     * StringUtils.getLevenshteinDistance("", "")              = 0
    2263     * StringUtils.getLevenshteinDistance("", "a")             = 1
    2264     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    2265     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    2266     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    2267     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    2268     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    2269     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    2270     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    2271     * </pre>
    2272     *
    2273     * @param s  the first String, must not be null
    2274     * @param t  the second String, must not be null
    2275     * @return result distance
    2276     * @throws IllegalArgumentException if either String input {@code null}
    2277     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
    2278     * getLevenshteinDistance(CharSequence, CharSequence)
    2279     * @deprecated As of 3.6, use Apache Commons Text
    2280     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2281     * LevenshteinDistance</a> instead
    2282     */
    2283    @Deprecated
    2284    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    2285        if (s == null || t == null) {
    2286            throw new IllegalArgumentException("Strings must not be null");
    2287        }
    2288
    2289        int n = s.length();
    2290        int m = t.length();
    2291
    2292        if (n == 0) {
    2293            return m;
    2294        }
    2295        if (m == 0) {
    2296            return n;
    2297        }
    2298
    2299        if (n > m) {
    2300            // swap the input strings to consume less memory
    2301            final CharSequence tmp = s;
    2302            s = t;
    2303            t = tmp;
    2304            n = m;
    2305            m = t.length();
    2306        }
    2307
    2308        final int[] p = new int[n + 1];
    2309        // indexes into strings s and t
    2310        int i; // iterates through s
    2311        int j; // iterates through t
    2312        int upperleft;
    2313        int upper;
    2314
    2315        char jOfT; // jth character of t
    2316        int cost;
    2317
    2318        for (i = 0; i <= n; i++) {
    2319            p[i] = i;
    2320        }
    2321
    2322        for (j = 1; j <= m; j++) {
    2323            upperleft = p[0];
    2324            jOfT = t.charAt(j - 1);
    2325            p[0] = j;
    2326
    2327            for (i = 1; i <= n; i++) {
    2328                upper = p[i];
    2329                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
    2330                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    2331                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
    2332                upperleft = upper;
    2333            }
    2334        }
    2335
    2336        return p[n];
    2337    }
    2338
    2339    /**
    2340     * Find the Levenshtein distance between two Strings if it's less than or equal to a given
    2341     * threshold.
    2342     *
    2343     * <p>This is the number of changes needed to change one String into
    2344     * another, where each change is a single character modification (deletion,
    2345     * insertion or substitution).</p>
    2346     *
    2347     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
    2348     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
    2349     * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
    2350     *
    2351     * <pre>
    2352     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
    2353     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
    2354     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
    2355     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
    2356     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
    2357     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
    2358     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
    2359     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
    2360     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
    2361     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
    2362     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
    2363     * </pre>
    2364     *
    2365     * @param s  the first String, must not be null
    2366     * @param t  the second String, must not be null
    2367     * @param threshold the target threshold, must not be negative
    2368     * @return result distance, or {@code -1} if the distance would be greater than the threshold
    2369     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
    2370     * @deprecated As of 3.6, use Apache Commons Text
    2371     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2372     * LevenshteinDistance</a> instead
    2373     */
    2374    @Deprecated
    2375    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
    2376        if (s == null || t == null) {
    2377            throw new IllegalArgumentException("Strings must not be null");
    2378        }
    2379        if (threshold < 0) {
    2380            throw new IllegalArgumentException("Threshold must not be negative");
    2381        }
    2382
    2383        /*
    2384        This implementation only computes the distance if it's less than or equal to the
    2385        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    2386        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    2387        computing a diagonal stripe of width 2k + 1 of the cost table.
    2388        It is also possible to use this to compute the unbounded Levenshtein distance by starting
    2389        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    2390        d is the distance.
    2391
    2392        One subtlety comes from needing to ignore entries on the border of our stripe
    2393        eg.
    2394        p[] = |#|#|#|*
    2395        d[] =  *|#|#|#|
    2396        We must ignore the entry to the left of the leftmost member
    2397        We must ignore the entry above the rightmost member
    2398
    2399        Another subtlety comes from our stripe running off the matrix if the strings aren't
    2400        of the same size.  Since string s is always swapped to be the shorter of the two,
    2401        the stripe will always run off to the upper right instead of the lower left of the matrix.
    2402
    2403        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    2404        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
    2405
    2406           1 2 3 4 5
    2407        1 |#|#| | | |
    2408        2 |#|#|#| | |
    2409        3 | |#|#|#| |
    2410        4 | | |#|#|#|
    2411        5 | | | |#|#|
    2412        6 | | | | |#|
    2413        7 | | | | | |
    2414
    2415        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    2416        into one of length 7 in edit distance of 1.
    2417
    2418        Additionally, this implementation decreases memory usage by using two
    2419        single-dimensional arrays and swapping them back and forth instead of allocating
    2420        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    2421        when it's detected that the stripe has run off the matrix and initially filling the arrays with
    2422        large values so that entries we don't compute are ignored.
    2423
    2424        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
    2425         */
    2426
    2427        int n = s.length(); // length of s
    2428        int m = t.length(); // length of t
    2429
    2430        // if one string is empty, the edit distance is necessarily the length of the other
    2431        if (n == 0) {
    2432            return m <= threshold ? m : -1;
    2433        }
    2434        if (m == 0) {
    2435            return n <= threshold ? n : -1;
    2436        }
    2437        if (Math.abs(n - m) > threshold) {
    2438            // no need to calculate the distance if the length difference is greater than the threshold
    2439            return -1;
    2440        }
    2441
    2442        if (n > m) {
    2443            // swap the two strings to consume less memory
    2444            final CharSequence tmp = s;
    2445            s = t;
    2446            t = tmp;
    2447            n = m;
    2448            m = t.length();
    2449        }
    2450
    2451        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
    2452        int[] d = new int[n + 1]; // cost array, horizontally
    2453        int[] tmp; // placeholder to assist in swapping p and d
    2454
    2455        // fill in starting table values
    2456        final int boundary = Math.min(n, threshold) + 1;
    2457        for (int i = 0; i < boundary; i++) {
    2458            p[i] = i;
    2459        }
    2460        // these fills ensure that the value above the rightmost entry of our
    2461        // stripe will be ignored in following loop iterations
    2462        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    2463        Arrays.fill(d, Integer.MAX_VALUE);
    2464
    2465        // iterates through t
    2466        for (int j = 1; j <= m; j++) {
    2467            final char jOfT = t.charAt(j - 1); // jth character of t
    2468            d[0] = j;
    2469
    2470            // compute stripe indices, constrain to array size
    2471            final int min = Math.max(1, j - threshold);
    2472            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
    2473
    2474            // the stripe may lead off of the table if s and t are of different sizes
    2475            if (min > max) {
    2476                return -1;
    2477            }
    2478
    2479            // ignore entry left of leftmost
    2480            if (min > 1) {
    2481                d[min - 1] = Integer.MAX_VALUE;
    2482            }
    2483
    2484            // iterates through [min, max] in s
    2485            for (int i = min; i <= max; i++) {
    2486                if (s.charAt(i - 1) == jOfT) {
    2487                    // diagonally left and up
    2488                    d[i] = p[i - 1];
    2489                } else {
    2490                    // 1 + minimum of cell to the left, to the top, diagonally left and up
    2491                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
    2492                }
    2493            }
    2494
    2495            // copy current distance counts to 'previous row' distance counts
    2496            tmp = p;
    2497            p = d;
    2498            d = tmp;
    2499        }
    2500
    2501        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    2502        // distance
    2503        if (p[n] <= threshold) {
    2504            return p[n];
    2505        }
    2506        return -1;
    2507    }
    2508
    2509    /**
    2510     * Finds the first index within a CharSequence, handling {@code null}.
    2511     * This method uses {@link String#indexOf(String, int)} if possible.
    2512     *
    2513     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    2514     *
    2515     * <pre>
    2516     * StringUtils.indexOf(null, *)          = -1
    2517     * StringUtils.indexOf(*, null)          = -1
    2518     * StringUtils.indexOf("", "")           = 0
    2519     * StringUtils.indexOf("", *)            = -1 (except when * = "")
    2520     * StringUtils.indexOf("aabaabaa", "a")  = 0
    2521     * StringUtils.indexOf("aabaabaa", "b")  = 2
    2522     * StringUtils.indexOf("aabaabaa", "ab") = 1
    2523     * StringUtils.indexOf("aabaabaa", "")   = 0
    2524     * </pre>
    2525     *
    2526     * @param seq  the CharSequence to check, may be null
    2527     * @param searchSeq  the CharSequence to find, may be null
    2528     * @return the first index of the search CharSequence,
    2529     *  -1 if no match or {@code null} string input
    2530     * @since 2.0
    2531     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
    2532     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}
    2533     */
    2534    @Deprecated
    2535    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
    2536        return Strings.CS.indexOf(seq, searchSeq);
    2537    }
    2538
    2539    /**
    2540     * Finds the first index within a CharSequence, handling {@code null}.
    2541     * This method uses {@link String#indexOf(String, int)} if possible.
    2542     *
    2543     * <p>A {@code null} CharSequence will return {@code -1}.
    2544     * A negative start position is treated as zero.
    2545     * An empty ("") search CharSequence always matches.
    2546     * A start position greater than the string length only matches
    2547     * an empty search CharSequence.</p>
    2548     *
    2549     * <pre>
    2550     * StringUtils.indexOf(null, *, *)          = -1
    2551     * StringUtils.indexOf(*, null, *)          = -1
    2552     * StringUtils.indexOf("", "", 0)           = 0
    2553     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    2554     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    2555     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    2556     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    2557     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    2558     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    2559     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    2560     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    2561     * StringUtils.indexOf("abc", "", 9)        = 3
    2562     * </pre>
    2563     *
    2564     * @param seq  the CharSequence to check, may be null
    2565     * @param searchSeq  the CharSequence to find, may be null
    2566     * @param startPos  the start position, negative treated as zero
    2567     * @return the first index of the search CharSequence (always &ge; startPos),
    2568     *  -1 if no match or {@code null} string input
    2569     * @since 2.0
    2570     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
    2571     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}
    2572     */
    2573    @Deprecated
    2574    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    2575        return Strings.CS.indexOf(seq, searchSeq, startPos);
    2576    }
    2577
    2578    /**
    2579     * Returns the index within {@code seq} of the first occurrence of
    2580     * the specified character. If a character with value
    2581     * {@code searchChar} occurs in the character sequence represented by
    2582     * {@code seq} {@link CharSequence} object, then the index (in Unicode
    2583     * code units) of the first such occurrence is returned. For
    2584     * values of {@code searchChar} in the range from 0 to 0xFFFF
    2585     * (inclusive), this is the smallest value <em>k</em> such that:
    2586     * <blockquote><pre>
    2587     * this.charAt(<em>k</em>) == searchChar
    2588     * </pre></blockquote>
    2589     * is true. For other values of {@code searchChar}, it is the
    2590     * smallest value <em>k</em> such that:
    2591     * <blockquote><pre>
    2592     * this.codePointAt(<em>k</em>) == searchChar
    2593     * </pre></blockquote>
    2594     * is true. In either case, if no such character occurs in {@code seq},
    2595     * then {@code INDEX_NOT_FOUND (-1)} is returned.
    2596     *
    2597     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
    2598     * return {@code INDEX_NOT_FOUND (-1)}.</p>
    2599     *
    2600     * <pre>
    2601     * StringUtils.indexOf(null, *)         = -1
    2602     * StringUtils.indexOf("", *)           = -1
    2603     * StringUtils.indexOf("aabaabaa", 'a') = 0
    2604     * StringUtils.indexOf("aabaabaa", 'b') = 2
    2605     * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
    2606     * </pre>
    2607     *
    2608     * @param seq  the CharSequence to check, may be null
    2609     * @param searchChar  the character to find
    2610     * @return the first index of the search character,
    2611     *  -1 if no match or {@code null} string input
    2612     * @since 2.0
    2613     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
    2614     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2615     */
    2616    public static int indexOf(final CharSequence seq, final int searchChar) {
    2617        if (isEmpty(seq)) {
    2618            return INDEX_NOT_FOUND;
    2619        }
    2620        return CharSequenceUtils.indexOf(seq, searchChar, 0);
    2621    }
    2622
    2623    /**
    2624     * Returns the index within {@code seq} of the first occurrence of the
    2625     * specified character, starting the search at the specified index.
    2626     * <p>
    2627     * If a character with value {@code searchChar} occurs in the
    2628     * character sequence represented by the {@code seq} {@link CharSequence}
    2629     * object at an index no smaller than {@code startPos}, then
    2630     * the index of the first such occurrence is returned. For values
    2631     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
    2632     * this is the smallest value <em>k</em> such that:
    2633     * <blockquote><pre>
    2634     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
    2635     * </pre></blockquote>
    2636     * is true. For other values of {@code searchChar}, it is the
    2637     * smallest value <em>k</em> such that:
    2638     * <blockquote><pre>
    2639     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
    2640     * </pre></blockquote>
    2641     * is true. In either case, if no such character occurs in {@code seq}
    2642     * at or after position {@code startPos}, then
    2643     * {@code -1} is returned.
    2644     *
    2645     * <p>
    2646     * There is no restriction on the value of {@code startPos}. If it
    2647     * is negative, it has the same effect as if it were zero: this entire
    2648     * string may be searched. If it is greater than the length of this
    2649     * string, it has the same effect as if it were equal to the length of
    2650     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
    2651     * {@code null} or empty ("") CharSequence will
    2652     * return {@code (INDEX_NOT_FOUND) -1}.
    2653     *
    2654     * <p>All indices are specified in {@code char} values
    2655     * (Unicode code units).
    2656     *
    2657     * <pre>
    2658     * StringUtils.indexOf(null, *, *)          = -1
    2659     * StringUtils.indexOf("", *, *)            = -1
    2660     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    2661     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    2662     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    2663     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    2664     * </pre>
    2665     *
    2666     * @param seq  the CharSequence to check, may be null
    2667     * @param searchChar  the character to find
    2668     * @param startPos  the start position, negative treated as zero
    2669     * @return the first index of the search character (always &ge; startPos),
    2670     *  -1 if no match or {@code null} string input
    2671     * @since 2.0
    2672     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
    2673     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2674     */
    2675    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
    2676        if (isEmpty(seq)) {
    2677            return INDEX_NOT_FOUND;
    2678        }
    2679        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
    2680    }
    2681
    2682    /**
    2683     * Search a CharSequence to find the first index of any
    2684     * character in the given set of characters.
    2685     *
    2686     * <p>A {@code null} String will return {@code -1}.
    2687     * A {@code null} or zero length search array will return {@code -1}.</p>
    2688     *
    2689     * <pre>
    2690     * StringUtils.indexOfAny(null, *)                  = -1
    2691     * StringUtils.indexOfAny("", *)                    = -1
    2692     * StringUtils.indexOfAny(*, null)                  = -1
    2693     * StringUtils.indexOfAny(*, [])                    = -1
    2694     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
    2695     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
    2696     * StringUtils.indexOfAny("aba", ['z'])             = -1
    2697     * </pre>
    2698     *
    2699     * @param cs  the CharSequence to check, may be null
    2700     * @param searchChars  the chars to search for, may be null
    2701     * @return the index of any of the chars, -1 if no match or null input
    2702     * @since 2.0
    2703     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2704     */
    2705    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    2706        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2707            return INDEX_NOT_FOUND;
    2708        }
    2709        final int csLen = cs.length();
    2710        final int csLast = csLen - 1;
    2711        final int searchLen = searchChars.length;
    2712        final int searchLast = searchLen - 1;
    2713        for (int i = 0; i < csLen; i++) {
    2714            final char ch = cs.charAt(i);
    2715            for (int j = 0; j < searchLen; j++) {
    2716                if (searchChars[j] == ch) {
    2717                    // ch is a supplementary character
    2718                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch) || searchChars[j + 1] == cs.charAt(i + 1)) {
    2719                        return i;
    2720                    }
    2721                }
    2722            }
    2723        }
    2724        return INDEX_NOT_FOUND;
    2725    }
    2726
    2727    /**
    2728     * Find the first index of any of a set of potential substrings.
    2729     *
    2730     * <p>A {@code null} CharSequence will return {@code -1}.
    2731     * A {@code null} or zero length search array will return {@code -1}.
    2732     * A {@code null} search array entry will be ignored, but a search
    2733     * array containing "" will return {@code 0} if {@code str} is not
    2734     * null. This method uses {@link String#indexOf(String)} if possible.</p>
    2735     *
    2736     * <pre>
    2737     * StringUtils.indexOfAny(null, *)                      = -1
    2738     * StringUtils.indexOfAny(*, null)                      = -1
    2739     * StringUtils.indexOfAny(*, [])                        = -1
    2740     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
    2741     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
    2742     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
    2743     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
    2744     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
    2745     * StringUtils.indexOfAny("", [""])                     = 0
    2746     * StringUtils.indexOfAny("", ["a"])                    = -1
    2747     * </pre>
    2748     *
    2749     * @param str  the CharSequence to check, may be null
    2750     * @param searchStrs  the CharSequences to search for, may be null
    2751     * @return the first index of any of the searchStrs in str, -1 if no match
    2752     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
    2753     */
    2754    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2755        if (str == null || searchStrs == null) {
    2756            return INDEX_NOT_FOUND;
    2757        }
    2758
    2759        // String's can't have a MAX_VALUEth index.
    2760        int ret = Integer.MAX_VALUE;
    2761
    2762        int tmp;
    2763        for (final CharSequence search : searchStrs) {
    2764            if (search == null) {
    2765                continue;
    2766            }
    2767            tmp = CharSequenceUtils.indexOf(str, search, 0);
    2768            if (tmp == INDEX_NOT_FOUND) {
    2769                continue;
    2770            }
    2771
    2772            if (tmp < ret) {
    2773                ret = tmp;
    2774            }
    2775        }
    2776
    2777        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
    2778    }
    2779
    2780    /**
    2781     * Search a CharSequence to find the first index of any
    2782     * character in the given set of characters.
    2783     *
    2784     * <p>A {@code null} String will return {@code -1}.
    2785     * A {@code null} search string will return {@code -1}.</p>
    2786     *
    2787     * <pre>
    2788     * StringUtils.indexOfAny(null, *)            = -1
    2789     * StringUtils.indexOfAny("", *)              = -1
    2790     * StringUtils.indexOfAny(*, null)            = -1
    2791     * StringUtils.indexOfAny(*, "")              = -1
    2792     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    2793     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    2794     * StringUtils.indexOfAny("aba", "z")         = -1
    2795     * </pre>
    2796     *
    2797     * @param cs  the CharSequence to check, may be null
    2798     * @param searchChars  the chars to search for, may be null
    2799     * @return the index of any of the chars, -1 if no match or null input
    2800     * @since 2.0
    2801     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    2802     */
    2803    public static int indexOfAny(final CharSequence cs, final String searchChars) {
    2804        if (isEmpty(cs) || isEmpty(searchChars)) {
    2805            return INDEX_NOT_FOUND;
    2806        }
    2807        return indexOfAny(cs, searchChars.toCharArray());
    2808    }
    2809
    2810    /**
    2811     * Searches a CharSequence to find the first index of any
    2812     * character not in the given set of characters, i.e.,
    2813     * find index i of first char in cs such that (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
    2814     *
    2815     * <p>A {@code null} CharSequence will return {@code -1}.
    2816     * A {@code null} or zero length search array will return {@code -1}.</p>
    2817     *
    2818     * <pre>
    2819     * StringUtils.indexOfAnyBut(null, *)                              = -1
    2820     * StringUtils.indexOfAnyBut("", *)                                = -1
    2821     * StringUtils.indexOfAnyBut(*, null)                              = -1
    2822     * StringUtils.indexOfAnyBut(*, [])                                = -1
    2823     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
    2824     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
    2825     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
    2826
    2827     * </pre>
    2828     *
    2829     * @param cs  the CharSequence to check, may be null
    2830     * @param searchChars  the chars to search for, may be null
    2831     * @return the index of any of the chars, -1 if no match or null input
    2832     * @since 2.0
    2833     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
    2834     */
    2835    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    2836        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2837            return INDEX_NOT_FOUND;
    2838        }
    2839        return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
    2840    }
    2841
    2842    /**
    2843     * Search a CharSequence to find the first index of any
    2844     * character not in the given set of characters, i.e.,
    2845     * find index i of first char in seq such that (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
    2846     *
    2847     * <p>A {@code null} CharSequence will return {@code -1}.
    2848     * A {@code null} or empty search string will return {@code -1}.</p>
    2849     *
    2850     * <pre>
    2851     * StringUtils.indexOfAnyBut(null, *)            = -1
    2852     * StringUtils.indexOfAnyBut("", *)              = -1
    2853     * StringUtils.indexOfAnyBut(*, null)            = -1
    2854     * StringUtils.indexOfAnyBut(*, "")              = -1
    2855     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    2856     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
    2857     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
    2858     * </pre>
    2859     *
    2860     * @param seq  the CharSequence to check, may be null
    2861     * @param searchChars  the chars to search for, may be null
    2862     * @return the index of any of the chars, -1 if no match or null input
    2863     * @since 2.0
    2864     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
    2865     */
    2866    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
    2867        if (isEmpty(seq) || isEmpty(searchChars)) {
    2868            return INDEX_NOT_FOUND;
    2869        }
    2870        final Set<Integer> searchSetCodePoints = searchChars.codePoints()
    2871                .boxed().collect(Collectors.toSet());
    2872        // advance character index from one interpreted codepoint to the next
    2873        for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
    2874            final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
    2875            if (!searchSetCodePoints.contains(curSeqCodePoint)) {
    2876                return curSeqCharIdx;
    2877            }
    2878            curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
    2879        }
    2880        return INDEX_NOT_FOUND;
    2881    }
    2882
    2883    /**
    2884     * Compares all CharSequences in an array and returns the index at which the
    2885     * CharSequences begin to differ.
    2886     *
    2887     * <p>For example,
    2888     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
    2889     *
    2890     * <pre>
    2891     * StringUtils.indexOfDifference(null)                             = -1
    2892     * StringUtils.indexOfDifference(new String[] {})                  = -1
    2893     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
    2894     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
    2895     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
    2896     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
    2897     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    2898     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    2899     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
    2900     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
    2901     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
    2902     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
    2903     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
    2904     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
    2905     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
    2906     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
    2907     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    2908     * </pre>
    2909     *
    2910     * @param css  array of CharSequences, entries may be null
    2911     * @return the index where the strings begin to differ; -1 if they are all equal
    2912     * @since 2.4
    2913     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    2914     */
    2915    public static int indexOfDifference(final CharSequence... css) {
    2916        if (ArrayUtils.getLength(css) <= 1) {
    2917            return INDEX_NOT_FOUND;
    2918        }
    2919        boolean anyStringNull = false;
    2920        boolean allStringsNull = true;
    2921        final int arrayLen = css.length;
    2922        int shortestStrLen = Integer.MAX_VALUE;
    2923        int longestStrLen = 0;
    2924
    2925        // find the min and max string lengths; this avoids checking to make
    2926        // sure we are not exceeding the length of the string each time through
    2927        // the bottom loop.
    2928        for (final CharSequence cs : css) {
    2929            if (cs == null) {
    2930                anyStringNull = true;
    2931                shortestStrLen = 0;
    2932            } else {
    2933                allStringsNull = false;
    2934                shortestStrLen = Math.min(cs.length(), shortestStrLen);
    2935                longestStrLen = Math.max(cs.length(), longestStrLen);
    2936            }
    2937        }
    2938
    2939        // handle lists containing all nulls or all empty strings
    2940        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
    2941            return INDEX_NOT_FOUND;
    2942        }
    2943
    2944        // handle lists containing some nulls or some empty strings
    2945        if (shortestStrLen == 0) {
    2946            return 0;
    2947        }
    2948
    2949        // find the position with the first difference across all strings
    2950        int firstDiff = -1;
    2951        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    2952            final char comparisonChar = css[0].charAt(stringPos);
    2953            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    2954                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    2955                    firstDiff = stringPos;
    2956                    break;
    2957                }
    2958            }
    2959            if (firstDiff != -1) {
    2960                break;
    2961            }
    2962        }
    2963
    2964        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    2965            // we compared all of the characters up to the length of the
    2966            // shortest string and didn't find a match, but the string lengths
    2967            // vary, so return the length of the shortest string.
    2968            return shortestStrLen;
    2969        }
    2970        return firstDiff;
    2971    }
    2972
    2973    /**
    2974     * Compares two CharSequences, and returns the index at which the
    2975     * CharSequences begin to differ.
    2976     *
    2977     * <p>For example,
    2978     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
    2979     *
    2980     * <pre>
    2981     * StringUtils.indexOfDifference(null, null)       = -1
    2982     * StringUtils.indexOfDifference("", "")           = -1
    2983     * StringUtils.indexOfDifference("", "abc")        = 0
    2984     * StringUtils.indexOfDifference("abc", "")        = 0
    2985     * StringUtils.indexOfDifference("abc", "abc")     = -1
    2986     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
    2987     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    2988     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
    2989     * </pre>
    2990     *
    2991     * @param cs1  the first CharSequence, may be null
    2992     * @param cs2  the second CharSequence, may be null
    2993     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
    2994     * @since 2.0
    2995     * @since 3.0 Changed signature from indexOfDifference(String, String) to
    2996     * indexOfDifference(CharSequence, CharSequence)
    2997     */
    2998    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
    2999        if (cs1 == cs2) {
    3000            return INDEX_NOT_FOUND;
    3001        }
    3002        if (cs1 == null || cs2 == null) {
    3003            return 0;
    3004        }
    3005        int i;
    3006        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    3007            if (cs1.charAt(i) != cs2.charAt(i)) {
    3008                break;
    3009            }
    3010        }
    3011        if (i < cs2.length() || i < cs1.length()) {
    3012            return i;
    3013        }
    3014        return INDEX_NOT_FOUND;
    3015    }
    3016
    3017    /**
    3018     * Case in-sensitive find of the first index within a CharSequence.
    3019     *
    3020     * <p>A {@code null} CharSequence will return {@code -1}.
    3021     * A negative start position is treated as zero.
    3022     * An empty ("") search CharSequence always matches.
    3023     * A start position greater than the string length only matches
    3024     * an empty search CharSequence.</p>
    3025     *
    3026     * <pre>
    3027     * StringUtils.indexOfIgnoreCase(null, *)          = -1
    3028     * StringUtils.indexOfIgnoreCase(*, null)          = -1
    3029     * StringUtils.indexOfIgnoreCase("", "")           = 0
    3030     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
    3031     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    3032     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    3033     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    3034     * </pre>
    3035     *
    3036     * @param str  the CharSequence to check, may be null
    3037     * @param searchStr  the CharSequence to find, may be null
    3038     * @return the first index of the search CharSequence,
    3039     *  -1 if no match or {@code null} string input
    3040     * @since 2.5
    3041     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
    3042     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}
    3043     */
    3044    @Deprecated
    3045    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    3046        return Strings.CI.indexOf(str, searchStr);
    3047    }
    3048
    3049    /**
    3050     * Case in-sensitive find of the first index within a CharSequence
    3051     * from the specified position.
    3052     *
    3053     * <p>A {@code null} CharSequence will return {@code -1}.
    3054     * A negative start position is treated as zero.
    3055     * An empty ("") search CharSequence always matches.
    3056     * A start position greater than the string length only matches
    3057     * an empty search CharSequence.</p>
    3058     *
    3059     * <pre>
    3060     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    3061     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    3062     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    3063     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    3064     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    3065     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    3066     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    3067     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    3068     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    3069     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    3070     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
    3071     * </pre>
    3072     *
    3073     * @param str  the CharSequence to check, may be null
    3074     * @param searchStr  the CharSequence to find, may be null
    3075     * @param startPos  the start position, negative treated as zero
    3076     * @return the first index of the search CharSequence (always &ge; startPos),
    3077     *  -1 if no match or {@code null} string input
    3078     * @since 2.5
    3079     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
    3080     * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}
    3081     */
    3082    @Deprecated
    3083    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
    3084        return Strings.CI.indexOf(str, searchStr, startPos);
    3085    }
    3086
    3087    /**
    3088     * Tests if all of the CharSequences are empty (""), null or whitespace only.
    3089     *
    3090     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3091     *
    3092     * <pre>
    3093     * StringUtils.isAllBlank(null)             = true
    3094     * StringUtils.isAllBlank(null, "foo")      = false
    3095     * StringUtils.isAllBlank(null, null)       = true
    3096     * StringUtils.isAllBlank("", "bar")        = false
    3097     * StringUtils.isAllBlank("bob", "")        = false
    3098     * StringUtils.isAllBlank("  bob  ", null)  = false
    3099     * StringUtils.isAllBlank(" ", "bar")       = false
    3100     * StringUtils.isAllBlank("foo", "bar")     = false
    3101     * StringUtils.isAllBlank(new String[] {})  = true
    3102     * </pre>
    3103     *
    3104     * @param css  the CharSequences to check, may be null or empty
    3105     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
    3106     * @since 3.6
    3107     */
    3108    public static boolean isAllBlank(final CharSequence... css) {
    3109        if (ArrayUtils.isEmpty(css)) {
    3110            return true;
    3111        }
    3112        for (final CharSequence cs : css) {
    3113            if (isNotBlank(cs)) {
    3114               return false;
    3115            }
    3116        }
    3117        return true;
    3118    }
    3119
    3120    /**
    3121     * Tests if all of the CharSequences are empty ("") or null.
    3122     *
    3123     * <pre>
    3124     * StringUtils.isAllEmpty(null)             = true
    3125     * StringUtils.isAllEmpty(null, "")         = true
    3126     * StringUtils.isAllEmpty(new String[] {})  = true
    3127     * StringUtils.isAllEmpty(null, "foo")      = false
    3128     * StringUtils.isAllEmpty("", "bar")        = false
    3129     * StringUtils.isAllEmpty("bob", "")        = false
    3130     * StringUtils.isAllEmpty("  bob  ", null)  = false
    3131     * StringUtils.isAllEmpty(" ", "bar")       = false
    3132     * StringUtils.isAllEmpty("foo", "bar")     = false
    3133     * </pre>
    3134     *
    3135     * @param css  the CharSequences to check, may be null or empty
    3136     * @return {@code true} if all of the CharSequences are empty or null
    3137     * @since 3.6
    3138     */
    3139    public static boolean isAllEmpty(final CharSequence... css) {
    3140        if (ArrayUtils.isEmpty(css)) {
    3141            return true;
    3142        }
    3143        for (final CharSequence cs : css) {
    3144            if (isNotEmpty(cs)) {
    3145                return false;
    3146            }
    3147        }
    3148        return true;
    3149    }
    3150
    3151    /**
    3152     * Tests if the CharSequence contains only lowercase characters.
    3153     *
    3154     * <p>{@code null} will return {@code false}.
    3155     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3156     *
    3157     * <pre>
    3158     * StringUtils.isAllLowerCase(null)   = false
    3159     * StringUtils.isAllLowerCase("")     = false
    3160     * StringUtils.isAllLowerCase("  ")   = false
    3161     * StringUtils.isAllLowerCase("abc")  = true
    3162     * StringUtils.isAllLowerCase("abC")  = false
    3163     * StringUtils.isAllLowerCase("ab c") = false
    3164     * StringUtils.isAllLowerCase("ab1c") = false
    3165     * StringUtils.isAllLowerCase("ab/c") = false
    3166     * </pre>
    3167     *
    3168     * @param cs  the CharSequence to check, may be null
    3169     * @return {@code true} if only contains lowercase characters, and is non-null
    3170     * @since 2.5
    3171     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    3172     */
    3173    public static boolean isAllLowerCase(final CharSequence cs) {
    3174        if (isEmpty(cs)) {
    3175            return false;
    3176        }
    3177        final int sz = cs.length();
    3178        for (int i = 0; i < sz; i++) {
    3179            if (!Character.isLowerCase(cs.charAt(i))) {
    3180                return false;
    3181            }
    3182        }
    3183        return true;
    3184    }
    3185
    3186    /**
    3187     * Tests if the CharSequence contains only uppercase characters.
    3188     *
    3189     * <p>{@code null} will return {@code false}.
    3190     * An empty String (length()=0) will return {@code false}.</p>
    3191     *
    3192     * <pre>
    3193     * StringUtils.isAllUpperCase(null)   = false
    3194     * StringUtils.isAllUpperCase("")     = false
    3195     * StringUtils.isAllUpperCase("  ")   = false
    3196     * StringUtils.isAllUpperCase("ABC")  = true
    3197     * StringUtils.isAllUpperCase("aBC")  = false
    3198     * StringUtils.isAllUpperCase("A C")  = false
    3199     * StringUtils.isAllUpperCase("A1C")  = false
    3200     * StringUtils.isAllUpperCase("A/C")  = false
    3201     * </pre>
    3202     *
    3203     * @param cs the CharSequence to check, may be null
    3204     * @return {@code true} if only contains uppercase characters, and is non-null
    3205     * @since 2.5
    3206     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    3207     */
    3208    public static boolean isAllUpperCase(final CharSequence cs) {
    3209        if (isEmpty(cs)) {
    3210            return false;
    3211        }
    3212        final int sz = cs.length();
    3213        for (int i = 0; i < sz; i++) {
    3214            if (!Character.isUpperCase(cs.charAt(i))) {
    3215                return false;
    3216            }
    3217        }
    3218        return true;
    3219    }
    3220
    3221    /**
    3222     * Tests if the CharSequence contains only Unicode letters.
    3223     *
    3224     * <p>{@code null} will return {@code false}.
    3225     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3226     *
    3227     * <pre>
    3228     * StringUtils.isAlpha(null)   = false
    3229     * StringUtils.isAlpha("")     = false
    3230     * StringUtils.isAlpha("  ")   = false
    3231     * StringUtils.isAlpha("abc")  = true
    3232     * StringUtils.isAlpha("ab2c") = false
    3233     * StringUtils.isAlpha("ab-c") = false
    3234     * </pre>
    3235     *
    3236     * @param cs  the CharSequence to check, may be null
    3237     * @return {@code true} if only contains letters, and is non-null
    3238     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    3239     * @since 3.0 Changed "" to return false and not true
    3240     */
    3241    public static boolean isAlpha(final CharSequence cs) {
    3242        if (isEmpty(cs)) {
    3243            return false;
    3244        }
    3245        final int sz = cs.length();
    3246        for (int i = 0; i < sz; i++) {
    3247            if (!Character.isLetter(cs.charAt(i))) {
    3248                return false;
    3249            }
    3250        }
    3251        return true;
    3252    }
    3253
    3254    /**
    3255     * Tests if the CharSequence contains only Unicode letters or digits.
    3256     *
    3257     * <p>{@code null} will return {@code false}.
    3258     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3259     *
    3260     * <pre>
    3261     * StringUtils.isAlphanumeric(null)   = false
    3262     * StringUtils.isAlphanumeric("")     = false
    3263     * StringUtils.isAlphanumeric("  ")   = false
    3264     * StringUtils.isAlphanumeric("abc")  = true
    3265     * StringUtils.isAlphanumeric("ab c") = false
    3266     * StringUtils.isAlphanumeric("ab2c") = true
    3267     * StringUtils.isAlphanumeric("ab-c") = false
    3268     * </pre>
    3269     *
    3270     * @param cs  the CharSequence to check, may be null
    3271     * @return {@code true} if only contains letters or digits,
    3272     *  and is non-null
    3273     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    3274     * @since 3.0 Changed "" to return false and not true
    3275     */
    3276    public static boolean isAlphanumeric(final CharSequence cs) {
    3277        if (isEmpty(cs)) {
    3278            return false;
    3279        }
    3280        final int sz = cs.length();
    3281        for (int i = 0; i < sz; i++) {
    3282            if (!Character.isLetterOrDigit(cs.charAt(i))) {
    3283                return false;
    3284            }
    3285        }
    3286        return true;
    3287    }
    3288
    3289    /**
    3290     * Tests if the CharSequence contains only Unicode letters, digits
    3291     * or space ({@code ' '}).
    3292     *
    3293     * <p>{@code null} will return {@code false}.
    3294     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3295     *
    3296     * <pre>
    3297     * StringUtils.isAlphanumericSpace(null)   = false
    3298     * StringUtils.isAlphanumericSpace("")     = true
    3299     * StringUtils.isAlphanumericSpace("  ")   = true
    3300     * StringUtils.isAlphanumericSpace("abc")  = true
    3301     * StringUtils.isAlphanumericSpace("ab c") = true
    3302     * StringUtils.isAlphanumericSpace("ab2c") = true
    3303     * StringUtils.isAlphanumericSpace("ab-c") = false
    3304     * </pre>
    3305     *
    3306     * @param cs  the CharSequence to check, may be null
    3307     * @return {@code true} if only contains letters, digits or space,
    3308     *  and is non-null
    3309     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    3310     */
    3311    public static boolean isAlphanumericSpace(final CharSequence cs) {
    3312        if (cs == null) {
    3313            return false;
    3314        }
    3315        final int sz = cs.length();
    3316        for (int i = 0; i < sz; i++) {
    3317            final char nowChar = cs.charAt(i);
    3318            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar)) {
    3319                return false;
    3320            }
    3321        }
    3322        return true;
    3323    }
    3324
    3325    /**
    3326     * Tests if the CharSequence contains only Unicode letters and
    3327     * space (' ').
    3328     *
    3329     * <p>{@code null} will return {@code false}
    3330     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3331     *
    3332     * <pre>
    3333     * StringUtils.isAlphaSpace(null)   = false
    3334     * StringUtils.isAlphaSpace("")     = true
    3335     * StringUtils.isAlphaSpace("  ")   = true
    3336     * StringUtils.isAlphaSpace("abc")  = true
    3337     * StringUtils.isAlphaSpace("ab c") = true
    3338     * StringUtils.isAlphaSpace("ab2c") = false
    3339     * StringUtils.isAlphaSpace("ab-c") = false
    3340     * </pre>
    3341     *
    3342     * @param cs  the CharSequence to check, may be null
    3343     * @return {@code true} if only contains letters and space,
    3344     *  and is non-null
    3345     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    3346     */
    3347    public static boolean isAlphaSpace(final CharSequence cs) {
    3348        if (cs == null) {
    3349            return false;
    3350        }
    3351        final int sz = cs.length();
    3352        for (int i = 0; i < sz; i++) {
    3353            final char nowChar = cs.charAt(i);
    3354            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
    3355                return false;
    3356            }
    3357        }
    3358        return true;
    3359    }
    3360
    3361    /**
    3362     * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
    3363     *
    3364     * <p>
    3365     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3366     * </p>
    3367     *
    3368     * <pre>
    3369     * StringUtils.isAnyBlank((String) null)    = true
    3370     * StringUtils.isAnyBlank((String[]) null)  = false
    3371     * StringUtils.isAnyBlank(null, "foo")      = true
    3372     * StringUtils.isAnyBlank(null, null)       = true
    3373     * StringUtils.isAnyBlank("", "bar")        = true
    3374     * StringUtils.isAnyBlank("bob", "")        = true
    3375     * StringUtils.isAnyBlank("  bob  ", null)  = true
    3376     * StringUtils.isAnyBlank(" ", "bar")       = true
    3377     * StringUtils.isAnyBlank(new String[] {})  = false
    3378     * StringUtils.isAnyBlank(new String[]{""}) = true
    3379     * StringUtils.isAnyBlank("foo", "bar")     = false
    3380     * </pre>
    3381     *
    3382     * @param css the CharSequences to check, may be null or empty
    3383     * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null})
    3384     * @see #isBlank(CharSequence)
    3385     * @since 3.2
    3386     */
    3387    public static boolean isAnyBlank(final CharSequence... css) {
    3388        if (ArrayUtils.isEmpty(css)) {
    3389            return false;
    3390        }
    3391        for (final CharSequence cs : css) {
    3392            if (isBlank(cs)) {
    3393                return true;
    3394            }
    3395        }
    3396        return false;
    3397    }
    3398
    3399    /**
    3400     * Tests if any of the CharSequences are empty ("") or null.
    3401     *
    3402     * <pre>
    3403     * StringUtils.isAnyEmpty((String) null)    = true
    3404     * StringUtils.isAnyEmpty((String[]) null)  = false
    3405     * StringUtils.isAnyEmpty(null, "foo")      = true
    3406     * StringUtils.isAnyEmpty("", "bar")        = true
    3407     * StringUtils.isAnyEmpty("bob", "")        = true
    3408     * StringUtils.isAnyEmpty("  bob  ", null)  = true
    3409     * StringUtils.isAnyEmpty(" ", "bar")       = false
    3410     * StringUtils.isAnyEmpty("foo", "bar")     = false
    3411     * StringUtils.isAnyEmpty(new String[]{})   = false
    3412     * StringUtils.isAnyEmpty(new String[]{""}) = true
    3413     * </pre>
    3414     *
    3415     * @param css  the CharSequences to check, may be null or empty
    3416     * @return {@code true} if any of the CharSequences are empty or null
    3417     * @since 3.2
    3418     */
    3419    public static boolean isAnyEmpty(final CharSequence... css) {
    3420        if (ArrayUtils.isEmpty(css)) {
    3421            return false;
    3422        }
    3423        for (final CharSequence cs : css) {
    3424            if (isEmpty(cs)) {
    3425                return true;
    3426            }
    3427        }
    3428        return false;
    3429    }
    3430
    3431    /**
    3432     * Tests if the CharSequence contains only ASCII printable characters.
    3433     *
    3434     * <p>{@code null} will return {@code false}.
    3435     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3436     *
    3437     * <pre>
    3438     * StringUtils.isAsciiPrintable(null)     = false
    3439     * StringUtils.isAsciiPrintable("")       = true
    3440     * StringUtils.isAsciiPrintable(" ")      = true
    3441     * StringUtils.isAsciiPrintable("Ceki")   = true
    3442     * StringUtils.isAsciiPrintable("ab2c")   = true
    3443     * StringUtils.isAsciiPrintable("!ab-c~") = true
    3444     * StringUtils.isAsciiPrintable("\u0020") = true
    3445     * StringUtils.isAsciiPrintable("\u0021") = true
    3446     * StringUtils.isAsciiPrintable("\u007e") = true
    3447     * StringUtils.isAsciiPrintable("\u007f") = false
    3448     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    3449     * </pre>
    3450     *
    3451     * @param cs the CharSequence to check, may be null
    3452     * @return {@code true} if every character is in the range
    3453     *  32 through 126
    3454     * @since 2.1
    3455     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    3456     */
    3457    public static boolean isAsciiPrintable(final CharSequence cs) {
    3458        if (cs == null) {
    3459            return false;
    3460        }
    3461        final int sz = cs.length();
    3462        for (int i = 0; i < sz; i++) {
    3463            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
    3464                return false;
    3465            }
    3466        }
    3467        return true;
    3468    }
    3469
    3470    /**
    3471     * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
    3472     *
    3473     * <pre>
    3474     * StringUtils.isBlank(null)      = true
    3475     * StringUtils.isBlank("")        = true
    3476     * StringUtils.isBlank(" ")       = true
    3477     * StringUtils.isBlank("bob")     = false
    3478     * StringUtils.isBlank("  bob  ") = false
    3479     * </pre>
    3480     *
    3481     * @param cs the CharSequence to check, may be null
    3482     * @return {@code true} if the CharSequence is null, empty or whitespace only
    3483     * @since 2.0
    3484     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    3485     */
    3486    public static boolean isBlank(final CharSequence cs) {
    3487        final int strLen = length(cs);
    3488        if (strLen == 0) {
    3489            return true;
    3490        }
    3491        for (int i = 0; i < strLen; i++) {
    3492            if (!Character.isWhitespace(cs.charAt(i))) {
    3493                return false;
    3494            }
    3495        }
    3496        return true;
    3497    }
    3498
    3499    /**
    3500     * Tests if a CharSequence is empty ("") or null.
    3501     *
    3502     * <pre>
    3503     * StringUtils.isEmpty(null)      = true
    3504     * StringUtils.isEmpty("")        = true
    3505     * StringUtils.isEmpty(" ")       = false
    3506     * StringUtils.isEmpty("bob")     = false
    3507     * StringUtils.isEmpty("  bob  ") = false
    3508     * </pre>
    3509     *
    3510     * <p>NOTE: This method changed in Lang version 2.0.
    3511     * It no longer trims the CharSequence.
    3512     * That functionality is available in isBlank().</p>
    3513     *
    3514     * @param cs  the CharSequence to check, may be null
    3515     * @return {@code true} if the CharSequence is empty or null
    3516     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    3517     */
    3518    public static boolean isEmpty(final CharSequence cs) {
    3519        return cs == null || cs.length() == 0;
    3520    }
    3521
    3522    /**
    3523     * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
    3524     *
    3525     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
    3526     * {@code false}.</p>
    3527     *
    3528     * <pre>
    3529     * StringUtils.isMixedCase(null)    = false
    3530     * StringUtils.isMixedCase("")      = false
    3531     * StringUtils.isMixedCase(" ")     = false
    3532     * StringUtils.isMixedCase("ABC")   = false
    3533     * StringUtils.isMixedCase("abc")   = false
    3534     * StringUtils.isMixedCase("aBc")   = true
    3535     * StringUtils.isMixedCase("A c")   = true
    3536     * StringUtils.isMixedCase("A1c")   = true
    3537     * StringUtils.isMixedCase("a/C")   = true
    3538     * StringUtils.isMixedCase("aC\t")  = true
    3539     * </pre>
    3540     *
    3541     * @param cs the CharSequence to check, may be null
    3542     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
    3543     * @since 3.5
    3544     */
    3545    public static boolean isMixedCase(final CharSequence cs) {
    3546        if (isEmpty(cs) || cs.length() == 1) {
    3547            return false;
    3548        }
    3549        boolean containsUppercase = false;
    3550        boolean containsLowercase = false;
    3551        final int sz = cs.length();
    3552        for (int i = 0; i < sz; i++) {
    3553            final char nowChar = cs.charAt(i);
    3554            if (Character.isUpperCase(nowChar)) {
    3555                containsUppercase = true;
    3556            } else if (Character.isLowerCase(nowChar)) {
    3557                containsLowercase = true;
    3558            }
    3559            if (containsUppercase && containsLowercase) {
    3560                return true;
    3561            }
    3562        }
    3563        return false;
    3564    }
    3565
    3566    /**
    3567     * Tests if none of the CharSequences are empty (""), null or whitespace only.
    3568     *
    3569     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3570     *
    3571     * <pre>
    3572     * StringUtils.isNoneBlank((String) null)    = false
    3573     * StringUtils.isNoneBlank((String[]) null)  = true
    3574     * StringUtils.isNoneBlank(null, "foo")      = false
    3575     * StringUtils.isNoneBlank(null, null)       = false
    3576     * StringUtils.isNoneBlank("", "bar")        = false
    3577     * StringUtils.isNoneBlank("bob", "")        = false
    3578     * StringUtils.isNoneBlank("  bob  ", null)  = false
    3579     * StringUtils.isNoneBlank(" ", "bar")       = false
    3580     * StringUtils.isNoneBlank(new String[] {})  = true
    3581     * StringUtils.isNoneBlank(new String[]{""}) = false
    3582     * StringUtils.isNoneBlank("foo", "bar")     = true
    3583     * </pre>
    3584     *
    3585     * @param css  the CharSequences to check, may be null or empty
    3586     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
    3587     * @since 3.2
    3588     */
    3589    public static boolean isNoneBlank(final CharSequence... css) {
    3590      return !isAnyBlank(css);
    3591    }
    3592
    3593    /**
    3594     * Tests if none of the CharSequences are empty ("") or null.
    3595     *
    3596     * <pre>
    3597     * StringUtils.isNoneEmpty((String) null)    = false
    3598     * StringUtils.isNoneEmpty((String[]) null)  = true
    3599     * StringUtils.isNoneEmpty(null, "foo")      = false
    3600     * StringUtils.isNoneEmpty("", "bar")        = false
    3601     * StringUtils.isNoneEmpty("bob", "")        = false
    3602     * StringUtils.isNoneEmpty("  bob  ", null)  = false
    3603     * StringUtils.isNoneEmpty(new String[] {})  = true
    3604     * StringUtils.isNoneEmpty(new String[]{""}) = false
    3605     * StringUtils.isNoneEmpty(" ", "bar")       = true
    3606     * StringUtils.isNoneEmpty("foo", "bar")     = true
    3607     * </pre>
    3608     *
    3609     * @param css  the CharSequences to check, may be null or empty
    3610     * @return {@code true} if none of the CharSequences are empty or null
    3611     * @since 3.2
    3612     */
    3613    public static boolean isNoneEmpty(final CharSequence... css) {
    3614      return !isAnyEmpty(css);
    3615    }
    3616
    3617    /**
    3618     * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
    3619     *
    3620     * <p>
    3621     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    3622     * </p>
    3623     *
    3624     * <pre>
    3625     * StringUtils.isNotBlank(null)      = false
    3626     * StringUtils.isNotBlank("")        = false
    3627     * StringUtils.isNotBlank(" ")       = false
    3628     * StringUtils.isNotBlank("bob")     = true
    3629     * StringUtils.isNotBlank("  bob  ") = true
    3630     * </pre>
    3631     *
    3632     * @param cs the CharSequence to check, may be null
    3633     * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null})
    3634     * @see #isBlank(CharSequence)
    3635     * @since 2.0
    3636     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    3637     */
    3638    public static boolean isNotBlank(final CharSequence cs) {
    3639        return !isBlank(cs);
    3640    }
    3641
    3642    /**
    3643     * Tests if a CharSequence is not empty ("") and not null.
    3644     *
    3645     * <pre>
    3646     * StringUtils.isNotEmpty(null)      = false
    3647     * StringUtils.isNotEmpty("")        = false
    3648     * StringUtils.isNotEmpty(" ")       = true
    3649     * StringUtils.isNotEmpty("bob")     = true
    3650     * StringUtils.isNotEmpty("  bob  ") = true
    3651     * </pre>
    3652     *
    3653     * @param cs  the CharSequence to check, may be null
    3654     * @return {@code true} if the CharSequence is not empty and not null
    3655     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    3656     */
    3657    public static boolean isNotEmpty(final CharSequence cs) {
    3658        return !isEmpty(cs);
    3659    }
    3660
    3661    /**
    3662     * Tests if the CharSequence contains only Unicode digits.
    3663     * A decimal point is not a Unicode digit and returns false.
    3664     *
    3665     * <p>{@code null} will return {@code false}.
    3666     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3667     *
    3668     * <p>Note that the method does not allow for a leading sign, either positive or negative.
    3669     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
    3670     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
    3671     * for int or long respectively.</p>
    3672     *
    3673     * <pre>
    3674     * StringUtils.isNumeric(null)   = false
    3675     * StringUtils.isNumeric("")     = false
    3676     * StringUtils.isNumeric("  ")   = false
    3677     * StringUtils.isNumeric("123")  = true
    3678     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    3679     * StringUtils.isNumeric("12 3") = false
    3680     * StringUtils.isNumeric("ab2c") = false
    3681     * StringUtils.isNumeric("12-3") = false
    3682     * StringUtils.isNumeric("12.3") = false
    3683     * StringUtils.isNumeric("-123") = false
    3684     * StringUtils.isNumeric("+123") = false
    3685     * </pre>
    3686     *
    3687     * @param cs  the CharSequence to check, may be null
    3688     * @return {@code true} if only contains digits, and is non-null
    3689     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    3690     * @since 3.0 Changed "" to return false and not true
    3691     */
    3692    public static boolean isNumeric(final CharSequence cs) {
    3693        if (isEmpty(cs)) {
    3694            return false;
    3695        }
    3696        final int sz = cs.length();
    3697        for (int i = 0; i < sz; i++) {
    3698            if (!Character.isDigit(cs.charAt(i))) {
    3699                return false;
    3700            }
    3701        }
    3702        return true;
    3703    }
    3704
    3705    /**
    3706     * Tests if the CharSequence contains only Unicode digits or space
    3707     * ({@code ' '}).
    3708     * A decimal point is not a Unicode digit and returns false.
    3709     *
    3710     * <p>{@code null} will return {@code false}.
    3711     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3712     *
    3713     * <pre>
    3714     * StringUtils.isNumericSpace(null)   = false
    3715     * StringUtils.isNumericSpace("")     = true
    3716     * StringUtils.isNumericSpace("  ")   = true
    3717     * StringUtils.isNumericSpace("123")  = true
    3718     * StringUtils.isNumericSpace("12 3") = true
    3719     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
    3720     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
    3721     * StringUtils.isNumericSpace("ab2c") = false
    3722     * StringUtils.isNumericSpace("12-3") = false
    3723     * StringUtils.isNumericSpace("12.3") = false
    3724     * </pre>
    3725     *
    3726     * @param cs  the CharSequence to check, may be null
    3727     * @return {@code true} if only contains digits or space,
    3728     *  and is non-null
    3729     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    3730     */
    3731    public static boolean isNumericSpace(final CharSequence cs) {
    3732        if (cs == null) {
    3733            return false;
    3734        }
    3735        final int sz = cs.length();
    3736        for (int i = 0; i < sz; i++) {
    3737            final char nowChar = cs.charAt(i);
    3738            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
    3739                return false;
    3740            }
    3741        }
    3742        return true;
    3743    }
    3744
    3745    /**
    3746     * Tests if the CharSequence contains only whitespace.
    3747     *
    3748     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3749     *
    3750     * <p>{@code null} will return {@code false}.
    3751     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3752     *
    3753     * <pre>
    3754     * StringUtils.isWhitespace(null)   = false
    3755     * StringUtils.isWhitespace("")     = true
    3756     * StringUtils.isWhitespace("  ")   = true
    3757     * StringUtils.isWhitespace("abc")  = false
    3758     * StringUtils.isWhitespace("ab2c") = false
    3759     * StringUtils.isWhitespace("ab-c") = false
    3760     * </pre>
    3761     *
    3762     * @param cs  the CharSequence to check, may be null
    3763     * @return {@code true} if only contains whitespace, and is non-null
    3764     * @since 2.0
    3765     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    3766     */
    3767    public static boolean isWhitespace(final CharSequence cs) {
    3768        if (cs == null) {
    3769            return false;
    3770        }
    3771        final int sz = cs.length();
    3772        for (int i = 0; i < sz; i++) {
    3773            if (!Character.isWhitespace(cs.charAt(i))) {
    3774                return false;
    3775            }
    3776        }
    3777        return true;
    3778    }
    3779
    3780    /**
    3781     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3782     *
    3783     * <p>
    3784     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3785     * by empty strings.
    3786     * </p>
    3787     *
    3788     * <pre>
    3789     * StringUtils.join(null, *)             = null
    3790     * StringUtils.join([], *)               = ""
    3791     * StringUtils.join([null], *)           = ""
    3792     * StringUtils.join([false, false], ';') = "false;false"
    3793     * </pre>
    3794     *
    3795     * @param array
    3796     *            the array of values to join together, may be null
    3797     * @param delimiter
    3798     *            the separator character to use
    3799     * @return the joined String, {@code null} if null array input
    3800     * @since 3.12.0
    3801     */
    3802    public static String join(final boolean[] array, final char delimiter) {
    3803        if (array == null) {
    3804            return null;
    3805        }
    3806        return join(array, delimiter, 0, array.length);
    3807    }
    3808
    3809    /**
    3810     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3811     *
    3812     * <p>
    3813     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3814     * by empty strings.
    3815     * </p>
    3816     *
    3817     * <pre>
    3818     * StringUtils.join(null, *)                  = null
    3819     * StringUtils.join([], *)                    = ""
    3820     * StringUtils.join([null], *)                = ""
    3821     * StringUtils.join([true, false, true], ';') = "true;false;true"
    3822     * </pre>
    3823     *
    3824     * @param array
    3825     *            the array of values to join together, may be null
    3826     * @param delimiter
    3827     *            the separator character to use
    3828     * @param startIndex
    3829     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3830     *            array
    3831     * @param endIndex
    3832     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3833     *            the array
    3834     * @return the joined String, {@code null} if null array input
    3835     * @since 3.12.0
    3836     */
    3837    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
    3838        if (array == null) {
    3839            return null;
    3840        }
    3841        if (endIndex - startIndex <= 0) {
    3842            return EMPTY;
    3843        }
    3844        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
    3845        for (int i = startIndex; i < endIndex; i++) {
    3846            stringBuilder
    3847                    .append(array[i])
    3848                    .append(delimiter);
    3849        }
    3850        return stringBuilder.substring(0, stringBuilder.length() - 1);
    3851    }
    3852
    3853    /**
    3854     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3855     *
    3856     * <p>
    3857     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3858     * by empty strings.
    3859     * </p>
    3860     *
    3861     * <pre>
    3862     * StringUtils.join(null, *)         = null
    3863     * StringUtils.join([], *)           = ""
    3864     * StringUtils.join([null], *)       = ""
    3865     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3866     * StringUtils.join([1, 2, 3], null) = "123"
    3867     * </pre>
    3868     *
    3869     * @param array
    3870     *            the array of values to join together, may be null
    3871     * @param delimiter
    3872     *            the separator character to use
    3873     * @return the joined String, {@code null} if null array input
    3874     * @since 3.2
    3875     */
    3876    public static String join(final byte[] array, final char delimiter) {
    3877        if (array == null) {
    3878            return null;
    3879        }
    3880        return join(array, delimiter, 0, array.length);
    3881    }
    3882
    3883    /**
    3884     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3885     *
    3886     * <p>
    3887     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3888     * by empty strings.
    3889     * </p>
    3890     *
    3891     * <pre>
    3892     * StringUtils.join(null, *)         = null
    3893     * StringUtils.join([], *)           = ""
    3894     * StringUtils.join([null], *)       = ""
    3895     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3896     * StringUtils.join([1, 2, 3], null) = "123"
    3897     * </pre>
    3898     *
    3899     * @param array
    3900     *            the array of values to join together, may be null
    3901     * @param delimiter
    3902     *            the separator character to use
    3903     * @param startIndex
    3904     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3905     *            array
    3906     * @param endIndex
    3907     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3908     *            the array
    3909     * @return the joined String, {@code null} if null array input
    3910     * @since 3.2
    3911     */
    3912    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
    3913        if (array == null) {
    3914            return null;
    3915        }
    3916        if (endIndex - startIndex <= 0) {
    3917            return EMPTY;
    3918        }
    3919        final StringBuilder stringBuilder = new StringBuilder();
    3920        for (int i = startIndex; i < endIndex; i++) {
    3921            stringBuilder
    3922                    .append(array[i])
    3923                    .append(delimiter);
    3924        }
    3925        return stringBuilder.substring(0, stringBuilder.length() - 1);
    3926    }
    3927
    3928    /**
    3929     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3930     *
    3931     * <p>
    3932     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3933     * by empty strings.
    3934     * </p>
    3935     *
    3936     * <pre>
    3937     * StringUtils.join(null, *)         = null
    3938     * StringUtils.join([], *)           = ""
    3939     * StringUtils.join([null], *)       = ""
    3940     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3941     * StringUtils.join([1, 2, 3], null) = "123"
    3942     * </pre>
    3943     *
    3944     * @param array
    3945     *            the array of values to join together, may be null
    3946     * @param delimiter
    3947     *            the separator character to use
    3948     * @return the joined String, {@code null} if null array input
    3949     * @since 3.2
    3950     */
    3951    public static String join(final char[] array, final char delimiter) {
    3952        if (array == null) {
    3953            return null;
    3954        }
    3955        return join(array, delimiter, 0, array.length);
    3956    }
    3957
    3958    /**
    3959     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3960     *
    3961     * <p>
    3962     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3963     * by empty strings.
    3964     * </p>
    3965     *
    3966     * <pre>
    3967     * StringUtils.join(null, *)         = null
    3968     * StringUtils.join([], *)           = ""
    3969     * StringUtils.join([null], *)       = ""
    3970     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3971     * StringUtils.join([1, 2, 3], null) = "123"
    3972     * </pre>
    3973     *
    3974     * @param array
    3975     *            the array of values to join together, may be null
    3976     * @param delimiter
    3977     *            the separator character to use
    3978     * @param startIndex
    3979     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3980     *            array
    3981     * @param endIndex
    3982     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3983     *            the array
    3984     * @return the joined String, {@code null} if null array input
    3985     * @since 3.2
    3986     */
    3987    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
    3988        if (array == null) {
    3989            return null;
    3990        }
    3991        if (endIndex - startIndex <= 0) {
    3992            return EMPTY;
    3993        }
    3994        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
    3995        for (int i = startIndex; i < endIndex; i++) {
    3996            stringBuilder
    3997                    .append(array[i])
    3998                    .append(delimiter);
    3999        }
    4000        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4001    }
    4002
    4003    /**
    4004     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4005     *
    4006     * <p>
    4007     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4008     * by empty strings.
    4009     * </p>
    4010     *
    4011     * <pre>
    4012     * StringUtils.join(null, *)               = null
    4013     * StringUtils.join([], *)                 = ""
    4014     * StringUtils.join([null], *)             = ""
    4015     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4016     * StringUtils.join([1, 2, 3], null) = "123"
    4017     * </pre>
    4018     *
    4019     * @param array
    4020     *            the array of values to join together, may be null
    4021     * @param delimiter
    4022     *            the separator character to use
    4023     * @return the joined String, {@code null} if null array input
    4024     * @since 3.2
    4025     */
    4026    public static String join(final double[] array, final char delimiter) {
    4027        if (array == null) {
    4028            return null;
    4029        }
    4030        return join(array, delimiter, 0, array.length);
    4031    }
    4032
    4033    /**
    4034     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4035     *
    4036     * <p>
    4037     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4038     * by empty strings.
    4039     * </p>
    4040     *
    4041     * <pre>
    4042     * StringUtils.join(null, *)               = null
    4043     * StringUtils.join([], *)                 = ""
    4044     * StringUtils.join([null], *)             = ""
    4045     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4046     * StringUtils.join([1, 2, 3], null) = "123"
    4047     * </pre>
    4048     *
    4049     * @param array
    4050     *            the array of values to join together, may be null
    4051     * @param delimiter
    4052     *            the separator character to use
    4053     * @param startIndex
    4054     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4055     *            array
    4056     * @param endIndex
    4057     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4058     *            the array
    4059     * @return the joined String, {@code null} if null array input
    4060     * @since 3.2
    4061     */
    4062    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
    4063        if (array == null) {
    4064            return null;
    4065        }
    4066        if (endIndex - startIndex <= 0) {
    4067            return EMPTY;
    4068        }
    4069        final StringBuilder stringBuilder = new StringBuilder();
    4070        for (int i = startIndex; i < endIndex; i++) {
    4071            stringBuilder
    4072                    .append(array[i])
    4073                    .append(delimiter);
    4074        }
    4075        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4076    }
    4077
    4078    /**
    4079     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4080     *
    4081     * <p>
    4082     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4083     * by empty strings.
    4084     * </p>
    4085     *
    4086     * <pre>
    4087     * StringUtils.join(null, *)               = null
    4088     * StringUtils.join([], *)                 = ""
    4089     * StringUtils.join([null], *)             = ""
    4090     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4091     * StringUtils.join([1, 2, 3], null) = "123"
    4092     * </pre>
    4093     *
    4094     * @param array
    4095     *            the array of values to join together, may be null
    4096     * @param delimiter
    4097     *            the separator character to use
    4098     * @return the joined String, {@code null} if null array input
    4099     * @since 3.2
    4100     */
    4101    public static String join(final float[] array, final char delimiter) {
    4102        if (array == null) {
    4103            return null;
    4104        }
    4105        return join(array, delimiter, 0, array.length);
    4106    }
    4107
    4108    /**
    4109     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4110     *
    4111     * <p>
    4112     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4113     * by empty strings.
    4114     * </p>
    4115     *
    4116     * <pre>
    4117     * StringUtils.join(null, *)               = null
    4118     * StringUtils.join([], *)                 = ""
    4119     * StringUtils.join([null], *)             = ""
    4120     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4121     * StringUtils.join([1, 2, 3], null) = "123"
    4122     * </pre>
    4123     *
    4124     * @param array
    4125     *            the array of values to join together, may be null
    4126     * @param delimiter
    4127     *            the separator character to use
    4128     * @param startIndex
    4129     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4130     *            array
    4131     * @param endIndex
    4132     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4133     *            the array
    4134     * @return the joined String, {@code null} if null array input
    4135     * @since 3.2
    4136     */
    4137    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
    4138        if (array == null) {
    4139            return null;
    4140        }
    4141        if (endIndex - startIndex <= 0) {
    4142            return EMPTY;
    4143        }
    4144        final StringBuilder stringBuilder = new StringBuilder();
    4145        for (int i = startIndex; i < endIndex; i++) {
    4146            stringBuilder
    4147                    .append(array[i])
    4148                    .append(delimiter);
    4149        }
    4150        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4151    }
    4152
    4153    /**
    4154     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4155     *
    4156     * <p>
    4157     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4158     * by empty strings.
    4159     * </p>
    4160     *
    4161     * <pre>
    4162     * StringUtils.join(null, *)               = null
    4163     * StringUtils.join([], *)                 = ""
    4164     * StringUtils.join([null], *)             = ""
    4165     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4166     * StringUtils.join([1, 2, 3], null) = "123"
    4167     * </pre>
    4168     *
    4169     * @param array
    4170     *            the array of values to join together, may be null
    4171     * @param separator
    4172     *            the separator character to use
    4173     * @return the joined String, {@code null} if null array input
    4174     * @since 3.2
    4175     */
    4176    public static String join(final int[] array, final char separator) {
    4177        if (array == null) {
    4178            return null;
    4179        }
    4180        return join(array, separator, 0, array.length);
    4181    }
    4182
    4183    /**
    4184     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4185     *
    4186     * <p>
    4187     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4188     * by empty strings.
    4189     * </p>
    4190     *
    4191     * <pre>
    4192     * StringUtils.join(null, *)               = null
    4193     * StringUtils.join([], *)                 = ""
    4194     * StringUtils.join([null], *)             = ""
    4195     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4196     * StringUtils.join([1, 2, 3], null) = "123"
    4197     * </pre>
    4198     *
    4199     * @param array
    4200     *            the array of values to join together, may be null
    4201     * @param delimiter
    4202     *            the separator character to use
    4203     * @param startIndex
    4204     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4205     *            array
    4206     * @param endIndex
    4207     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4208     *            the array
    4209     * @return the joined String, {@code null} if null array input
    4210     * @since 3.2
    4211     */
    4212    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
    4213        if (array == null) {
    4214            return null;
    4215        }
    4216        if (endIndex - startIndex <= 0) {
    4217            return EMPTY;
    4218        }
    4219        final StringBuilder stringBuilder = new StringBuilder();
    4220        for (int i = startIndex; i < endIndex; i++) {
    4221            stringBuilder
    4222                    .append(array[i])
    4223                    .append(delimiter);
    4224        }
    4225        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4226    }
    4227
    4228    /**
    4229     * Joins the elements of the provided {@link Iterable} into
    4230     * a single String containing the provided elements.
    4231     *
    4232     * <p>No delimiter is added before or after the list. Null objects or empty
    4233     * strings within the iteration are represented by empty strings.</p>
    4234     *
    4235     * <p>See the examples here: {@link #join(Object[],char)}.</p>
    4236     *
    4237     * @param iterable  the {@link Iterable} providing the values to join together, may be null
    4238     * @param separator  the separator character to use
    4239     * @return the joined String, {@code null} if null iterator input
    4240     * @since 2.3
    4241     */
    4242    public static String join(final Iterable<?> iterable, final char separator) {
    4243        return iterable != null ? join(iterable.iterator(), separator) : null;
    4244    }
    4245
    4246    /**
    4247     * Joins the elements of the provided {@link Iterable} into
    4248     * a single String containing the provided elements.
    4249     *
    4250     * <p>No delimiter is added before or after the list.
    4251     * A {@code null} separator is the same as an empty String ("").</p>
    4252     *
    4253     * <p>See the examples here: {@link #join(Object[],String)}.</p>
    4254     *
    4255     * @param iterable  the {@link Iterable} providing the values to join together, may be null
    4256     * @param separator  the separator character to use, null treated as ""
    4257     * @return the joined String, {@code null} if null iterator input
    4258     * @since 2.3
    4259     */
    4260    public static String join(final Iterable<?> iterable, final String separator) {
    4261        return iterable != null ? join(iterable.iterator(), separator) : null;
    4262    }
    4263
    4264    /**
    4265     * Joins the elements of the provided {@link Iterator} into
    4266     * a single String containing the provided elements.
    4267     *
    4268     * <p>No delimiter is added before or after the list. Null objects or empty
    4269     * strings within the iteration are represented by empty strings.</p>
    4270     *
    4271     * <p>See the examples here: {@link #join(Object[],char)}.</p>
    4272     *
    4273     * @param iterator  the {@link Iterator} of values to join together, may be null
    4274     * @param separator  the separator character to use
    4275     * @return the joined String, {@code null} if null iterator input
    4276     * @since 2.0
    4277     */
    4278    public static String join(final Iterator<?> iterator, final char separator) {
    4279        // handle null, zero and one elements before building a buffer
    4280        if (iterator == null) {
    4281            return null;
    4282        }
    4283        if (!iterator.hasNext()) {
    4284            return EMPTY;
    4285        }
    4286        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
    4287    }
    4288
    4289    /**
    4290     * Joins the elements of the provided {@link Iterator} into
    4291     * a single String containing the provided elements.
    4292     *
    4293     * <p>No delimiter is added before or after the list.
    4294     * A {@code null} separator is the same as an empty String ("").</p>
    4295     *
    4296     * <p>See the examples here: {@link #join(Object[],String)}.</p>
    4297     *
    4298     * @param iterator  the {@link Iterator} of values to join together, may be null
    4299     * @param separator  the separator character to use, null treated as ""
    4300     * @return the joined String, {@code null} if null iterator input
    4301     */
    4302    public static String join(final Iterator<?> iterator, final String separator) {
    4303        // handle null, zero and one elements before building a buffer
    4304        if (iterator == null) {
    4305            return null;
    4306        }
    4307        if (!iterator.hasNext()) {
    4308            return EMPTY;
    4309        }
    4310        return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
    4311    }
    4312
    4313    /**
    4314     * Joins the elements of the provided {@link List} into a single String
    4315     * containing the provided list of elements.
    4316     *
    4317     * <p>No delimiter is added before or after the list.
    4318     * Null objects or empty strings within the array are represented by
    4319     * empty strings.</p>
    4320     *
    4321     * <pre>
    4322     * StringUtils.join(null, *)               = null
    4323     * StringUtils.join([], *)                 = ""
    4324     * StringUtils.join([null], *)             = ""
    4325     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4326     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4327     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4328     * </pre>
    4329     *
    4330     * @param list  the {@link List} of values to join together, may be null
    4331     * @param separator  the separator character to use
    4332     * @param startIndex the first index to start joining from.  It is
    4333     * an error to pass in a start index past the end of the list
    4334     * @param endIndex the index to stop joining from (exclusive). It is
    4335     * an error to pass in an end index past the end of the list
    4336     * @return the joined String, {@code null} if null list input
    4337     * @since 3.8
    4338     */
    4339    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
    4340        if (list == null) {
    4341            return null;
    4342        }
    4343        final int noOfItems = endIndex - startIndex;
    4344        if (noOfItems <= 0) {
    4345            return EMPTY;
    4346        }
    4347        final List<?> subList = list.subList(startIndex, endIndex);
    4348        return join(subList.iterator(), separator);
    4349    }
    4350
    4351    /**
    4352     * Joins the elements of the provided {@link List} into a single String
    4353     * containing the provided list of elements.
    4354     *
    4355     * <p>No delimiter is added before or after the list.
    4356     * Null objects or empty strings within the array are represented by
    4357     * empty strings.</p>
    4358     *
    4359     * <pre>
    4360     * StringUtils.join(null, *)               = null
    4361     * StringUtils.join([], *)                 = ""
    4362     * StringUtils.join([null], *)             = ""
    4363     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4364     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4365     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4366     * </pre>
    4367     *
    4368     * @param list  the {@link List} of values to join together, may be null
    4369     * @param separator  the separator character to use
    4370     * @param startIndex the first index to start joining from.  It is
    4371     * an error to pass in a start index past the end of the list
    4372     * @param endIndex the index to stop joining from (exclusive). It is
    4373     * an error to pass in an end index past the end of the list
    4374     * @return the joined String, {@code null} if null list input
    4375     * @since 3.8
    4376     */
    4377    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
    4378        if (list == null) {
    4379            return null;
    4380        }
    4381        final int noOfItems = endIndex - startIndex;
    4382        if (noOfItems <= 0) {
    4383            return EMPTY;
    4384        }
    4385        final List<?> subList = list.subList(startIndex, endIndex);
    4386        return join(subList.iterator(), separator);
    4387    }
    4388
    4389    /**
    4390     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4391     *
    4392     * <p>
    4393     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4394     * by empty strings.
    4395     * </p>
    4396     *
    4397     * <pre>
    4398     * StringUtils.join(null, *)               = null
    4399     * StringUtils.join([], *)                 = ""
    4400     * StringUtils.join([null], *)             = ""
    4401     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4402     * StringUtils.join([1, 2, 3], null) = "123"
    4403     * </pre>
    4404     *
    4405     * @param array
    4406     *            the array of values to join together, may be null
    4407     * @param separator
    4408     *            the separator character to use
    4409     * @return the joined String, {@code null} if null array input
    4410     * @since 3.2
    4411     */
    4412    public static String join(final long[] array, final char separator) {
    4413        if (array == null) {
    4414            return null;
    4415        }
    4416        return join(array, separator, 0, array.length);
    4417    }
    4418
    4419    /**
    4420     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4421     *
    4422     * <p>
    4423     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4424     * by empty strings.
    4425     * </p>
    4426     *
    4427     * <pre>
    4428     * StringUtils.join(null, *)               = null
    4429     * StringUtils.join([], *)                 = ""
    4430     * StringUtils.join([null], *)             = ""
    4431     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4432     * StringUtils.join([1, 2, 3], null) = "123"
    4433     * </pre>
    4434     *
    4435     * @param array
    4436     *            the array of values to join together, may be null
    4437     * @param delimiter
    4438     *            the separator character to use
    4439     * @param startIndex
    4440     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4441     *            array
    4442     * @param endIndex
    4443     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4444     *            the array
    4445     * @return the joined String, {@code null} if null array input
    4446     * @since 3.2
    4447     */
    4448    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
    4449        if (array == null) {
    4450            return null;
    4451        }
    4452        if (endIndex - startIndex <= 0) {
    4453            return EMPTY;
    4454        }
    4455        final StringBuilder stringBuilder = new StringBuilder();
    4456        for (int i = startIndex; i < endIndex; i++) {
    4457            stringBuilder
    4458                    .append(array[i])
    4459                    .append(delimiter);
    4460        }
    4461        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4462    }
    4463
    4464    /**
    4465     * Joins the elements of the provided array into a single String
    4466     * containing the provided list of elements.
    4467     *
    4468     * <p>No delimiter is added before or after the list.
    4469     * Null objects or empty strings within the array are represented by
    4470     * empty strings.</p>
    4471     *
    4472     * <pre>
    4473     * StringUtils.join(null, *)               = null
    4474     * StringUtils.join([], *)                 = ""
    4475     * StringUtils.join([null], *)             = ""
    4476     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4477     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4478     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4479     * </pre>
    4480     *
    4481     * @param array  the array of values to join together, may be null
    4482     * @param delimiter  the separator character to use
    4483     * @return the joined String, {@code null} if null array input
    4484     * @since 2.0
    4485     */
    4486    public static String join(final Object[] array, final char delimiter) {
    4487        if (array == null) {
    4488            return null;
    4489        }
    4490        return join(array, delimiter, 0, array.length);
    4491    }
    4492
    4493    /**
    4494     * Joins the elements of the provided array into a single String
    4495     * containing the provided list of elements.
    4496     *
    4497     * <p>No delimiter is added before or after the list.
    4498     * Null objects or empty strings within the array are represented by
    4499     * empty strings.</p>
    4500     *
    4501     * <pre>
    4502     * StringUtils.join(null, *)               = null
    4503     * StringUtils.join([], *)                 = ""
    4504     * StringUtils.join([null], *)             = ""
    4505     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4506     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4507     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4508     * </pre>
    4509     *
    4510     * @param array  the array of values to join together, may be null
    4511     * @param delimiter  the separator character to use
    4512     * @param startIndex the first index to start joining from.  It is
    4513     * an error to pass in a start index past the end of the array
    4514     * @param endIndex the index to stop joining from (exclusive). It is
    4515     * an error to pass in an end index past the end of the array
    4516     * @return the joined String, {@code null} if null array input
    4517     * @since 2.0
    4518     */
    4519    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
    4520        return join(array, String.valueOf(delimiter), startIndex, endIndex);
    4521    }
    4522
    4523    /**
    4524     * Joins the elements of the provided array into a single String
    4525     * containing the provided list of elements.
    4526     *
    4527     * <p>No delimiter is added before or after the list.
    4528     * A {@code null} separator is the same as an empty String ("").
    4529     * Null objects or empty strings within the array are represented by
    4530     * empty strings.</p>
    4531     *
    4532     * <pre>
    4533     * StringUtils.join(null, *)                = null
    4534     * StringUtils.join([], *)                  = ""
    4535     * StringUtils.join([null], *)              = ""
    4536     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    4537     * StringUtils.join(["a", "b", "c"], null)  = "abc"
    4538     * StringUtils.join(["a", "b", "c"], "")    = "abc"
    4539     * StringUtils.join([null, "", "a"], ',')   = ",,a"
    4540     * </pre>
    4541     *
    4542     * @param array  the array of values to join together, may be null
    4543     * @param delimiter  the separator character to use, null treated as ""
    4544     * @return the joined String, {@code null} if null array input
    4545     */
    4546    public static String join(final Object[] array, final String delimiter) {
    4547        return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
    4548    }
    4549
    4550    /**
    4551     * Joins the elements of the provided array into a single String
    4552     * containing the provided list of elements.
    4553     *
    4554     * <p>No delimiter is added before or after the list.
    4555     * A {@code null} separator is the same as an empty String ("").
    4556     * Null objects or empty strings within the array are represented by
    4557     * empty strings.</p>
    4558     *
    4559     * <pre>
    4560     * StringUtils.join(null, *, *, *)                = null
    4561     * StringUtils.join([], *, *, *)                  = ""
    4562     * StringUtils.join([null], *, *, *)              = ""
    4563     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
    4564     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
    4565     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
    4566     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
    4567     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
    4568     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
    4569     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
    4570     * </pre>
    4571     *
    4572     * @param array  the array of values to join together, may be null
    4573     * @param delimiter  the separator character to use, null treated as ""
    4574     * @param startIndex the first index to start joining from.
    4575     * @param endIndex the index to stop joining from (exclusive).
    4576     * @return the joined String, {@code null} if null array input; or the empty string
    4577     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
    4578     * {@code endIndex - startIndex}
    4579     * @throws ArrayIndexOutOfBoundsException ife<br>
    4580     * {@code startIndex < 0} or <br>
    4581     * {@code startIndex >= array.length()} or <br>
    4582     * {@code endIndex < 0} or <br>
    4583     * {@code endIndex > array.length()}
    4584     */
    4585    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
    4586        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
    4587            .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
    4588    }
    4589
    4590    /**
    4591     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4592     *
    4593     * <p>
    4594     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4595     * by empty strings.
    4596     * </p>
    4597     *
    4598     * <pre>
    4599     * StringUtils.join(null, *)               = null
    4600     * StringUtils.join([], *)                 = ""
    4601     * StringUtils.join([null], *)             = ""
    4602     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4603     * StringUtils.join([1, 2, 3], null) = "123"
    4604     * </pre>
    4605     *
    4606     * @param array
    4607     *            the array of values to join together, may be null
    4608     * @param delimiter
    4609     *            the separator character to use
    4610     * @return the joined String, {@code null} if null array input
    4611     * @since 3.2
    4612     */
    4613    public static String join(final short[] array, final char delimiter) {
    4614        if (array == null) {
    4615            return null;
    4616        }
    4617        return join(array, delimiter, 0, array.length);
    4618    }
    4619
    4620    /**
    4621     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4622     *
    4623     * <p>
    4624     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4625     * by empty strings.
    4626     * </p>
    4627     *
    4628     * <pre>
    4629     * StringUtils.join(null, *)               = null
    4630     * StringUtils.join([], *)                 = ""
    4631     * StringUtils.join([null], *)             = ""
    4632     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4633     * StringUtils.join([1, 2, 3], null) = "123"
    4634     * </pre>
    4635     *
    4636     * @param array
    4637     *            the array of values to join together, may be null
    4638     * @param delimiter
    4639     *            the separator character to use
    4640     * @param startIndex
    4641     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4642     *            array
    4643     * @param endIndex
    4644     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4645     *            the array
    4646     * @return the joined String, {@code null} if null array input
    4647     * @since 3.2
    4648     */
    4649    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
    4650        if (array == null) {
    4651            return null;
    4652        }
    4653        if (endIndex - startIndex <= 0) {
    4654            return EMPTY;
    4655        }
    4656        final StringBuilder stringBuilder = new StringBuilder();
    4657        for (int i = startIndex; i < endIndex; i++) {
    4658            stringBuilder
    4659                    .append(array[i])
    4660                    .append(delimiter);
    4661        }
    4662        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4663    }
    4664
    4665    /**
    4666     * Joins the elements of the provided array into a single String
    4667     * containing the provided list of elements.
    4668     *
    4669     * <p>No separator is added to the joined String.
    4670     * Null objects or empty strings within the array are represented by
    4671     * empty strings.</p>
    4672     *
    4673     * <pre>
    4674     * StringUtils.join(null)            = null
    4675     * StringUtils.join([])              = ""
    4676     * StringUtils.join([null])          = ""
    4677     * StringUtils.join(["a", "b", "c"]) = "abc"
    4678     * StringUtils.join([null, "", "a"]) = "a"
    4679     * </pre>
    4680     *
    4681     * @param <T> the specific type of values to join together
    4682     * @param elements  the values to join together, may be null
    4683     * @return the joined String, {@code null} if null array input
    4684     * @since 2.0
    4685     * @since 3.0 Changed signature to use varargs
    4686     */
    4687    @SafeVarargs
    4688    public static <T> String join(final T... elements) {
    4689        return join(elements, null);
    4690    }
    4691
    4692    /**
    4693     * Joins the elements of the provided varargs into a
    4694     * single String containing the provided elements.
    4695     *
    4696     * <p>No delimiter is added before or after the list.
    4697     * {@code null} elements and separator are treated as empty Strings ("").</p>
    4698     *
    4699     * <pre>
    4700     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
    4701     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
    4702     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
    4703     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
    4704     * </pre>
    4705     *
    4706     * @param delimiter the separator character to use, null treated as ""
    4707     * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
    4708     * @return the joined String.
    4709     * @throws IllegalArgumentException if a null varargs is provided
    4710     * @since 3.5
    4711     */
    4712    public static String joinWith(final String delimiter, final Object... array) {
    4713        if (array == null) {
    4714            throw new IllegalArgumentException("Object varargs must not be null");
    4715        }
    4716        return join(array, delimiter);
    4717    }
    4718
    4719    /**
    4720     * Finds the last index within a CharSequence, handling {@code null}.
    4721     * This method uses {@link String#lastIndexOf(String)} if possible.
    4722     *
    4723     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    4724     *
    4725     * <pre>
    4726     * StringUtils.lastIndexOf(null, *)          = -1
    4727     * StringUtils.lastIndexOf(*, null)          = -1
    4728     * StringUtils.lastIndexOf("", "")           = 0
    4729     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    4730     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    4731     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    4732     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    4733     * </pre>
    4734     *
    4735     * @param seq  the CharSequence to check, may be null
    4736     * @param searchSeq  the CharSequence to find, may be null
    4737     * @return the last index of the search String,
    4738     *  -1 if no match or {@code null} string input
    4739     * @since 2.0
    4740     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
    4741     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}
    4742     */
    4743    @Deprecated
    4744    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
    4745        return Strings.CS.lastIndexOf(seq, searchSeq);
    4746    }
    4747
    4748    /**
    4749     * Finds the last index within a CharSequence, handling {@code null}.
    4750     * This method uses {@link String#lastIndexOf(String, int)} if possible.
    4751     *
    4752     * <p>A {@code null} CharSequence will return {@code -1}.
    4753     * A negative start position returns {@code -1}.
    4754     * An empty ("") search CharSequence always matches unless the start position is negative.
    4755     * A start position greater than the string length searches the whole string.
    4756     * The search starts at the startPos and works backwards; matches starting after the start
    4757     * position are ignored.
    4758     * </p>
    4759     *
    4760     * <pre>
    4761     * StringUtils.lastIndexOf(null, *, *)          = -1
    4762     * StringUtils.lastIndexOf(*, null, *)          = -1
    4763     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    4764     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    4765     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    4766     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    4767     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    4768     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    4769     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    4770     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
    4771     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
    4772     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
    4773     * </pre>
    4774     *
    4775     * @param seq  the CharSequence to check, may be null
    4776     * @param searchSeq  the CharSequence to find, may be null
    4777     * @param startPos  the start position, negative treated as zero
    4778     * @return the last index of the search CharSequence (always &le; startPos),
    4779     *  -1 if no match or {@code null} string input
    4780     * @since 2.0
    4781     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
    4782     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}
    4783     */
    4784    @Deprecated
    4785    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    4786        return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
    4787    }
    4788
    4789    /**
    4790     * Returns the index within {@code seq} of the last occurrence of
    4791     * the specified character. For values of {@code searchChar} in the
    4792     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
    4793     * units) returned is the largest value <em>k</em> such that:
    4794     * <blockquote><pre>
    4795     * this.charAt(<em>k</em>) == searchChar
    4796     * </pre></blockquote>
    4797     * is true. For other values of {@code searchChar}, it is the
    4798     * largest value <em>k</em> such that:
    4799     * <blockquote><pre>
    4800     * this.codePointAt(<em>k</em>) == searchChar
    4801     * </pre></blockquote>
    4802     * is true.  In either case, if no such character occurs in this
    4803     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4804     * {@link CharSequence} will return {@code -1}. The
    4805     * {@code seq} {@link CharSequence} object is searched backwards
    4806     * starting at the last character.
    4807     *
    4808     * <pre>
    4809     * StringUtils.lastIndexOf(null, *)         = -1
    4810     * StringUtils.lastIndexOf("", *)           = -1
    4811     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    4812     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    4813     * </pre>
    4814     *
    4815     * @param seq  the {@link CharSequence} to check, may be null
    4816     * @param searchChar  the character to find
    4817     * @return the last index of the search character,
    4818     *  -1 if no match or {@code null} string input
    4819     * @since 2.0
    4820     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
    4821     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    4822     */
    4823    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
    4824        if (isEmpty(seq)) {
    4825            return INDEX_NOT_FOUND;
    4826        }
    4827        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
    4828    }
    4829
    4830    /**
    4831     * Returns the index within {@code seq} of the last occurrence of
    4832     * the specified character, searching backward starting at the
    4833     * specified index. For values of {@code searchChar} in the range
    4834     * from 0 to 0xFFFF (inclusive), the index returned is the largest
    4835     * value <em>k</em> such that:
    4836     * <blockquote><pre>
    4837     * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
    4838     * </pre></blockquote>
    4839     * is true. For other values of {@code searchChar}, it is the
    4840     * largest value <em>k</em> such that:
    4841     * <blockquote><pre>
    4842     * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
    4843     * </pre></blockquote>
    4844     * is true. In either case, if no such character occurs in {@code seq}
    4845     * at or before position {@code startPos}, then
    4846     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4847     * {@link CharSequence} will return {@code -1}. A start position greater
    4848     * than the string length searches the whole string.
    4849     * The search starts at the {@code startPos} and works backwards;
    4850     * matches starting after the start position are ignored.
    4851     *
    4852     * <p>All indices are specified in {@code char} values
    4853     * (Unicode code units).
    4854     *
    4855     * <pre>
    4856     * StringUtils.lastIndexOf(null, *, *)          = -1
    4857     * StringUtils.lastIndexOf("", *,  *)           = -1
    4858     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    4859     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    4860     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    4861     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    4862     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    4863     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    4864     * </pre>
    4865     *
    4866     * @param seq  the CharSequence to check, may be null
    4867     * @param searchChar  the character to find
    4868     * @param startPos  the start position
    4869     * @return the last index of the search character (always &le; startPos),
    4870     *  -1 if no match or {@code null} string input
    4871     * @since 2.0
    4872     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
    4873     */
    4874    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
    4875        if (isEmpty(seq)) {
    4876            return INDEX_NOT_FOUND;
    4877        }
    4878        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
    4879    }
    4880
    4881    /**
    4882     * Find the latest index of any substring in a set of potential substrings.
    4883     *
    4884     * <p>A {@code null} CharSequence will return {@code -1}.
    4885     * A {@code null} search array will return {@code -1}.
    4886     * A {@code null} or zero length search array entry will be ignored,
    4887     * but a search array containing "" will return the length of {@code str}
    4888     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
    4889     *
    4890     * <pre>
    4891     * StringUtils.lastIndexOfAny(null, *)                    = -1
    4892     * StringUtils.lastIndexOfAny(*, null)                    = -1
    4893     * StringUtils.lastIndexOfAny(*, [])                      = -1
    4894     * StringUtils.lastIndexOfAny(*, [null])                  = -1
    4895     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
    4896     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
    4897     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    4898     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    4899     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
    4900     * </pre>
    4901     *
    4902     * @param str  the CharSequence to check, may be null
    4903     * @param searchStrs  the CharSequences to search for, may be null
    4904     * @return the last index of any of the CharSequences, -1 if no match
    4905     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
    4906     */
    4907    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    4908        if (str == null || searchStrs == null) {
    4909            return INDEX_NOT_FOUND;
    4910        }
    4911        int ret = INDEX_NOT_FOUND;
    4912        int tmp;
    4913        for (final CharSequence search : searchStrs) {
    4914            if (search == null) {
    4915                continue;
    4916            }
    4917            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
    4918            if (tmp > ret) {
    4919                ret = tmp;
    4920            }
    4921        }
    4922        return ret;
    4923    }
    4924
    4925    /**
    4926     * Case in-sensitive find of the last index within a CharSequence.
    4927     *
    4928     * <p>A {@code null} CharSequence will return {@code -1}.
    4929     * A negative start position returns {@code -1}.
    4930     * An empty ("") search CharSequence always matches unless the start position is negative.
    4931     * A start position greater than the string length searches the whole string.</p>
    4932     *
    4933     * <pre>
    4934     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    4935     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    4936     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    4937     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    4938     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    4939     * </pre>
    4940     *
    4941     * @param str  the CharSequence to check, may be null
    4942     * @param searchStr  the CharSequence to find, may be null
    4943     * @return the first index of the search CharSequence,
    4944     *  -1 if no match or {@code null} string input
    4945     * @since 2.5
    4946     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
    4947     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}
    4948     */
    4949    @Deprecated
    4950    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    4951        return Strings.CI.lastIndexOf(str, searchStr);
    4952    }
    4953
    4954    /**
    4955     * Case in-sensitive find of the last index within a CharSequence
    4956     * from the specified position.
    4957     *
    4958     * <p>A {@code null} CharSequence will return {@code -1}.
    4959     * A negative start position returns {@code -1}.
    4960     * An empty ("") search CharSequence always matches unless the start position is negative.
    4961     * A start position greater than the string length searches the whole string.
    4962     * The search starts at the startPos and works backwards; matches starting after the start
    4963     * position are ignored.
    4964     * </p>
    4965     *
    4966     * <pre>
    4967     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    4968     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    4969     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    4970     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    4971     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    4972     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    4973     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    4974     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    4975     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    4976     * </pre>
    4977     *
    4978     * @param str  the CharSequence to check, may be null
    4979     * @param searchStr  the CharSequence to find, may be null
    4980     * @param startPos  the start position
    4981     * @return the last index of the search CharSequence (always &le; startPos),
    4982     *  -1 if no match or {@code null} input
    4983     * @since 2.5
    4984     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
    4985     * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}
    4986     */
    4987    @Deprecated
    4988    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
    4989        return Strings.CI.lastIndexOf(str, searchStr, startPos);
    4990    }
    4991
    4992    /**
    4993     * Finds the n-th last index within a String, handling {@code null}.
    4994     * This method uses {@link String#lastIndexOf(String)}.
    4995     *
    4996     * <p>A {@code null} String will return {@code -1}.</p>
    4997     *
    4998     * <pre>
    4999     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    5000     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    5001     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    5002     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    5003     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    5004     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    5005     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    5006     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    5007     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    5008     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    5009     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    5010     * </pre>
    5011     *
    5012     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
    5013     *
    5014     * <pre>
    5015     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    5016     * </pre>
    5017     *
    5018     * @param str  the CharSequence to check, may be null
    5019     * @param searchStr  the CharSequence to find, may be null
    5020     * @param ordinal  the n-th last {@code searchStr} to find
    5021     * @return the n-th last index of the search CharSequence,
    5022     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5023     * @since 2.5
    5024     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
    5025     */
    5026    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5027        return ordinalIndexOf(str, searchStr, ordinal, true);
    5028    }
    5029
    5030    /**
    5031     * Gets the leftmost {@code len} characters of a String.
    5032     *
    5033     * <p>If {@code len} characters are not available, or the
    5034     * String is {@code null}, the String will be returned without
    5035     * an exception. An empty String is returned if len is negative.</p>
    5036     *
    5037     * <pre>
    5038     * StringUtils.left(null, *)    = null
    5039     * StringUtils.left(*, -ve)     = ""
    5040     * StringUtils.left("", *)      = ""
    5041     * StringUtils.left("abc", 0)   = ""
    5042     * StringUtils.left("abc", 2)   = "ab"
    5043     * StringUtils.left("abc", 4)   = "abc"
    5044     * </pre>
    5045     *
    5046     * @param str  the String to get the leftmost characters from, may be null
    5047     * @param len  the length of the required String
    5048     * @return the leftmost characters, {@code null} if null String input
    5049     */
    5050    public static String left(final String str, final int len) {
    5051        if (str == null) {
    5052            return null;
    5053        }
    5054        if (len < 0) {
    5055            return EMPTY;
    5056        }
    5057        if (str.length() <= len) {
    5058            return str;
    5059        }
    5060        return str.substring(0, len);
    5061    }
    5062
    5063    /**
    5064     * Left pad a String with spaces (' ').
    5065     *
    5066     * <p>The String is padded to the size of {@code size}.</p>
    5067     *
    5068     * <pre>
    5069     * StringUtils.leftPad(null, *)   = null
    5070     * StringUtils.leftPad("", 3)     = "   "
    5071     * StringUtils.leftPad("bat", 3)  = "bat"
    5072     * StringUtils.leftPad("bat", 5)  = "  bat"
    5073     * StringUtils.leftPad("bat", 1)  = "bat"
    5074     * StringUtils.leftPad("bat", -1) = "bat"
    5075     * </pre>
    5076     *
    5077     * @param str  the String to pad out, may be null
    5078     * @param size  the size to pad to
    5079     * @return left padded String or original String if no padding is necessary,
    5080     *  {@code null} if null String input
    5081     */
    5082    public static String leftPad(final String str, final int size) {
    5083        return leftPad(str, size, ' ');
    5084    }
    5085
    5086    /**
    5087     * Left pad a String with a specified character.
    5088     *
    5089     * <p>Pad to a size of {@code size}.</p>
    5090     *
    5091     * <pre>
    5092     * StringUtils.leftPad(null, *, *)     = null
    5093     * StringUtils.leftPad("", 3, 'z')     = "zzz"
    5094     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    5095     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    5096     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    5097     * StringUtils.leftPad("bat", -1, 'z') = "bat"
    5098     * </pre>
    5099     *
    5100     * @param str  the String to pad out, may be null
    5101     * @param size  the size to pad to
    5102     * @param padChar  the character to pad with
    5103     * @return left padded String or original String if no padding is necessary,
    5104     *  {@code null} if null String input
    5105     * @since 2.0
    5106     */
    5107    public static String leftPad(final String str, final int size, final char padChar) {
    5108        if (str == null) {
    5109            return null;
    5110        }
    5111        final int pads = size - str.length();
    5112        if (pads <= 0) {
    5113            return str; // returns original String when possible
    5114        }
    5115        if (pads > PAD_LIMIT) {
    5116            return leftPad(str, size, String.valueOf(padChar));
    5117        }
    5118        return repeat(padChar, pads).concat(str);
    5119    }
    5120
    5121    /**
    5122     * Left pad a String with a specified String.
    5123     *
    5124     * <p>Pad to a size of {@code size}.</p>
    5125     *
    5126     * <pre>
    5127     * StringUtils.leftPad(null, *, *)      = null
    5128     * StringUtils.leftPad("", 3, "z")      = "zzz"
    5129     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    5130     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    5131     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    5132     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    5133     * StringUtils.leftPad("bat", -1, "yz") = "bat"
    5134     * StringUtils.leftPad("bat", 5, null)  = "  bat"
    5135     * StringUtils.leftPad("bat", 5, "")    = "  bat"
    5136     * </pre>
    5137     *
    5138     * @param str  the String to pad out, may be null
    5139     * @param size  the size to pad to
    5140     * @param padStr  the String to pad with, null or empty treated as single space
    5141     * @return left padded String or original String if no padding is necessary,
    5142     *  {@code null} if null String input
    5143     */
    5144    public static String leftPad(final String str, final int size, String padStr) {
    5145        if (str == null) {
    5146            return null;
    5147        }
    5148        if (isEmpty(padStr)) {
    5149            padStr = SPACE;
    5150        }
    5151        final int padLen = padStr.length();
    5152        final int strLen = str.length();
    5153        final int pads = size - strLen;
    5154        if (pads <= 0) {
    5155            return str; // returns original String when possible
    5156        }
    5157        if (padLen == 1 && pads <= PAD_LIMIT) {
    5158            return leftPad(str, size, padStr.charAt(0));
    5159        }
    5160
    5161        if (pads == padLen) {
    5162            return padStr.concat(str);
    5163        }
    5164        if (pads < padLen) {
    5165            return padStr.substring(0, pads).concat(str);
    5166        }
    5167        final char[] padding = new char[pads];
    5168        final char[] padChars = padStr.toCharArray();
    5169        for (int i = 0; i < pads; i++) {
    5170            padding[i] = padChars[i % padLen];
    5171        }
    5172        return new String(padding).concat(str);
    5173    }
    5174
    5175    /**
    5176     * Gets a CharSequence length or {@code 0} if the CharSequence is
    5177     * {@code null}.
    5178     *
    5179     * @param cs
    5180     *            a CharSequence or {@code null}
    5181     * @return CharSequence length or {@code 0} if the CharSequence is
    5182     *         {@code null}.
    5183     * @since 2.4
    5184     * @since 3.0 Changed signature from length(String) to length(CharSequence)
    5185     */
    5186    public static int length(final CharSequence cs) {
    5187        return cs == null ? 0 : cs.length();
    5188    }
    5189
    5190    /**
    5191     * Converts a String to lower case as per {@link String#toLowerCase()}.
    5192     *
    5193     * <p>A {@code null} input String returns {@code null}.</p>
    5194     *
    5195     * <pre>
    5196     * StringUtils.lowerCase(null)  = null
    5197     * StringUtils.lowerCase("")    = ""
    5198     * StringUtils.lowerCase("aBc") = "abc"
    5199     * </pre>
    5200     *
    5201     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
    5202     * the result of this method is affected by the current locale.
    5203     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    5204     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    5205     *
    5206     * @param str  the String to lower case, may be null
    5207     * @return the lower cased String, {@code null} if null String input
    5208     */
    5209    public static String lowerCase(final String str) {
    5210        if (str == null) {
    5211            return null;
    5212        }
    5213        return str.toLowerCase();
    5214    }
    5215
    5216    /**
    5217     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
    5218     *
    5219     * <p>A {@code null} input String returns {@code null}.</p>
    5220     *
    5221     * <pre>
    5222     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    5223     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    5224     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    5225     * </pre>
    5226     *
    5227     * @param str  the String to lower case, may be null
    5228     * @param locale  the locale that defines the case transformation rules, must not be null
    5229     * @return the lower cased String, {@code null} if null String input
    5230     * @since 2.5
    5231     */
    5232    public static String lowerCase(final String str, final Locale locale) {
    5233        if (str == null) {
    5234            return null;
    5235        }
    5236        return str.toLowerCase(LocaleUtils.toLocale(locale));
    5237    }
    5238
    5239    private static int[] matches(final CharSequence first, final CharSequence second) {
    5240        final CharSequence max;
    5241        final CharSequence min;
    5242        if (first.length() > second.length()) {
    5243            max = first;
    5244            min = second;
    5245        } else {
    5246            max = second;
    5247            min = first;
    5248        }
    5249        final int range = Math.max(max.length() / 2 - 1, 0);
    5250        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
    5251        final boolean[] matchFlags = new boolean[max.length()];
    5252        int matches = 0;
    5253        for (int mi = 0; mi < min.length(); mi++) {
    5254            final char c1 = min.charAt(mi);
    5255            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
    5256                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
    5257                    matchIndexes[mi] = xi;
    5258                    matchFlags[xi] = true;
    5259                    matches++;
    5260                    break;
    5261                }
    5262            }
    5263        }
    5264        final char[] ms1 = new char[matches];
    5265        final char[] ms2 = new char[matches];
    5266        for (int i = 0, si = 0; i < min.length(); i++) {
    5267            if (matchIndexes[i] != -1) {
    5268                ms1[si] = min.charAt(i);
    5269                si++;
    5270            }
    5271        }
    5272        for (int i = 0, si = 0; i < max.length(); i++) {
    5273            if (matchFlags[i]) {
    5274                ms2[si] = max.charAt(i);
    5275                si++;
    5276            }
    5277        }
    5278        int transpositions = 0;
    5279        for (int mi = 0; mi < ms1.length; mi++) {
    5280            if (ms1[mi] != ms2[mi]) {
    5281                transpositions++;
    5282            }
    5283        }
    5284        int prefix = 0;
    5285        for (int mi = 0; mi < min.length(); mi++) {
    5286            if (first.charAt(mi) != second.charAt(mi)) {
    5287                break;
    5288            }
    5289            prefix++;
    5290        }
    5291        return new int[] { matches, transpositions / 2, prefix, max.length() };
    5292    }
    5293
    5294    /**
    5295     * Gets {@code len} characters from the middle of a String.
    5296     *
    5297     * <p>If {@code len} characters are not available, the remainder
    5298     * of the String will be returned without an exception. If the
    5299     * String is {@code null}, {@code null} will be returned.
    5300     * An empty String is returned if len is negative or exceeds the
    5301     * length of {@code str}.</p>
    5302     *
    5303     * <pre>
    5304     * StringUtils.mid(null, *, *)    = null
    5305     * StringUtils.mid(*, *, -ve)     = ""
    5306     * StringUtils.mid("", 0, *)      = ""
    5307     * StringUtils.mid("abc", 0, 2)   = "ab"
    5308     * StringUtils.mid("abc", 0, 4)   = "abc"
    5309     * StringUtils.mid("abc", 2, 4)   = "c"
    5310     * StringUtils.mid("abc", 4, 2)   = ""
    5311     * StringUtils.mid("abc", -2, 2)  = "ab"
    5312     * </pre>
    5313     *
    5314     * @param str  the String to get the characters from, may be null
    5315     * @param pos  the position to start from, negative treated as zero
    5316     * @param len  the length of the required String
    5317     * @return the middle characters, {@code null} if null String input
    5318     */
    5319    public static String mid(final String str, int pos, final int len) {
    5320        if (str == null) {
    5321            return null;
    5322        }
    5323        if (len < 0 || pos > str.length()) {
    5324            return EMPTY;
    5325        }
    5326        if (pos < 0) {
    5327            pos = 0;
    5328        }
    5329        if (str.length() <= pos + len) {
    5330            return str.substring(pos);
    5331        }
    5332        return str.substring(pos, pos + len);
    5333    }
    5334
    5335    /**
    5336     * Similar to <a
    5337     * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
    5338     * -space</a>
    5339     *
    5340     * <p>
    5341     * The function returns the argument string with whitespace normalized by using
    5342     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
    5343     * and then replacing sequences of whitespace characters by a single space.
    5344     * </p>
    5345     * In XML Whitespace characters are the same as those allowed by the <a
    5346     * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
    5347     * <p>
    5348     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
    5349     *
    5350     * <p>For reference:</p>
    5351     * <ul>
    5352     * <li>\x0B = vertical tab</li>
    5353     * <li>\f = #xC = form feed</li>
    5354     * <li>#x20 = space</li>
    5355     * <li>#x9 = \t</li>
    5356     * <li>#xA = \n</li>
    5357     * <li>#xD = \r</li>
    5358     * </ul>
    5359     *
    5360     * <p>
    5361     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
    5362     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
    5363     * ends of this String.
    5364     * </p>
    5365     *
    5366     * @see Pattern
    5367     * @see #trim(String)
    5368     * @see <a
    5369     *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
    5370     * @param str the source String to normalize whitespaces from, may be null
    5371     * @return the modified string with whitespace normalized, {@code null} if null String input
    5372     * @since 3.0
    5373     */
    5374    public static String normalizeSpace(final String str) {
    5375        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
    5376        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
    5377        if (isEmpty(str)) {
    5378            return str;
    5379        }
    5380        final int size = str.length();
    5381        final char[] newChars = new char[size];
    5382        int count = 0;
    5383        int whitespacesCount = 0;
    5384        boolean startWhitespaces = true;
    5385        for (int i = 0; i < size; i++) {
    5386            final char actualChar = str.charAt(i);
    5387            final boolean isWhitespace = Character.isWhitespace(actualChar);
    5388            if (isWhitespace) {
    5389                if (whitespacesCount == 0 && !startWhitespaces) {
    5390                    newChars[count++] = SPACE.charAt(0);
    5391                }
    5392                whitespacesCount++;
    5393            } else {
    5394                startWhitespaces = false;
    5395                newChars[count++] = actualChar == 160 ? 32 : actualChar;
    5396                whitespacesCount = 0;
    5397            }
    5398        }
    5399        if (startWhitespaces) {
    5400            return EMPTY;
    5401        }
    5402        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
    5403    }
    5404
    5405    /**
    5406     * Finds the n-th index within a CharSequence, handling {@code null}.
    5407     * This method uses {@link String#indexOf(String)} if possible.
    5408     * <p><strong>Note:</strong> The code starts looking for a match at the start of the target,
    5409     * incrementing the starting index by one after each successful match
    5410     * (unless {@code searchStr} is an empty string in which case the position
    5411     * is never incremented and {@code 0} is returned immediately).
    5412     * This means that matches may overlap.</p>
    5413     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5414     *
    5415     * <pre>
    5416     * StringUtils.ordinalIndexOf(null, *, *)          = -1
    5417     * StringUtils.ordinalIndexOf(*, null, *)          = -1
    5418     * StringUtils.ordinalIndexOf("", "", *)           = 0
    5419     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    5420     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    5421     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    5422     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    5423     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    5424     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    5425     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    5426     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    5427     * </pre>
    5428     *
    5429     * <p>Matches may overlap:</p>
    5430     * <pre>
    5431     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
    5432     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
    5433     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
    5434     *
    5435     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
    5436     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
    5437     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
    5438     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
    5439     * </pre>
    5440     *
    5441     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
    5442     *
    5443     * <pre>
    5444     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    5445     * </pre>
    5446     *
    5447     * @param str  the CharSequence to check, may be null
    5448     * @param searchStr  the CharSequence to find, may be null
    5449     * @param ordinal  the n-th {@code searchStr} to find
    5450     * @return the n-th index of the search CharSequence,
    5451     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5452     * @since 2.1
    5453     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
    5454     */
    5455    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5456        return ordinalIndexOf(str, searchStr, ordinal, false);
    5457    }
    5458
    5459    /**
    5460     * Finds the n-th index within a String, handling {@code null}.
    5461     * This method uses {@link String#indexOf(String)} if possible.
    5462     * <p>Note that matches may overlap<p>
    5463     *
    5464     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5465     *
    5466     * @param str  the CharSequence to check, may be null
    5467     * @param searchStr  the CharSequence to find, may be null
    5468     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
    5469     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
    5470     * @return the n-th index of the search CharSequence,
    5471     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5472     */
    5473    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
    5474    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
    5475        if (str == null || searchStr == null || ordinal <= 0) {
    5476            return INDEX_NOT_FOUND;
    5477        }
    5478        if (searchStr.length() == 0) {
    5479            return lastIndex ? str.length() : 0;
    5480        }
    5481        int found = 0;
    5482        // set the initial index beyond the end of the string
    5483        // this is to allow for the initial index decrement/increment
    5484        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    5485        do {
    5486            if (lastIndex) {
    5487                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
    5488            } else {
    5489                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
    5490            }
    5491            if (index < 0) {
    5492                return index;
    5493            }
    5494            found++;
    5495        } while (found < ordinal);
    5496        return index;
    5497    }
    5498
    5499    /**
    5500     * Overlays part of a String with another String.
    5501     *
    5502     * <p>A {@code null} string input returns {@code null}.
    5503     * A negative index is treated as zero.
    5504     * An index greater than the string length is treated as the string length.
    5505     * The start index is always the smaller of the two indices.</p>
    5506     *
    5507     * <pre>
    5508     * StringUtils.overlay(null, *, *, *)            = null
    5509     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    5510     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    5511     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    5512     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    5513     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    5514     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    5515     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    5516     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    5517     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    5518     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    5519     * </pre>
    5520     *
    5521     * @param str  the String to do overlaying in, may be null
    5522     * @param overlay  the String to overlay, may be null
    5523     * @param start  the position to start overlaying at
    5524     * @param end  the position to stop overlaying before
    5525     * @return overlayed String, {@code null} if null String input
    5526     * @since 2.0
    5527     */
    5528    public static String overlay(final String str, String overlay, int start, int end) {
    5529        if (str == null) {
    5530            return null;
    5531        }
    5532        if (overlay == null) {
    5533            overlay = EMPTY;
    5534        }
    5535        final int len = str.length();
    5536        if (start < 0) {
    5537            start = 0;
    5538        }
    5539        if (start > len) {
    5540            start = len;
    5541        }
    5542        if (end < 0) {
    5543            end = 0;
    5544        }
    5545        if (end > len) {
    5546            end = len;
    5547        }
    5548        if (start > end) {
    5549            final int temp = start;
    5550            start = end;
    5551            end = temp;
    5552        }
    5553        return str.substring(0, start) +
    5554            overlay +
    5555            str.substring(end);
    5556    }
    5557
    5558    /**
    5559     * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
    5560     *
    5561     * <pre>
    5562     * StringUtils.prependIfMissing(null, null) = null
    5563     * StringUtils.prependIfMissing("abc", null) = "abc"
    5564     * StringUtils.prependIfMissing("", "xyz") = "xyz"
    5565     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
    5566     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
    5567     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
    5568     * </pre>
    5569     * <p>
    5570     * With additional prefixes,
    5571     * </p>
    5572     *
    5573     * <pre>
    5574     * StringUtils.prependIfMissing(null, null, null) = null
    5575     * StringUtils.prependIfMissing("abc", null, null) = "abc"
    5576     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
    5577     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5578     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
    5579     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
    5580     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
    5581     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
    5582     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
    5583     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
    5584     * </pre>
    5585     *
    5586     * @param str      The string.
    5587     * @param prefix   The prefix to prepend to the start of the string.
    5588     * @param prefixes Additional prefixes that are valid.
    5589     * @return A new String if prefix was prepended, the same string otherwise.
    5590     * @since 3.2
    5591     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
    5592     *             CharSequence...)}
    5593     */
    5594    @Deprecated
    5595    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5596        return Strings.CS.prependIfMissing(str, prefix, prefixes);
    5597    }
    5598
    5599    /**
    5600     * Prepends the prefix to the start of the string if the string does not
    5601     * already start, case-insensitive, with any of the prefixes.
    5602     *
    5603     * <pre>
    5604     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
    5605     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
    5606     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
    5607     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
    5608     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
    5609     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
    5610     * </pre>
    5611     * <p>With additional prefixes,</p>
    5612     * <pre>
    5613     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
    5614     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
    5615     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
    5616     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5617     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    5618     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
    5619     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
    5620     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
    5621     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
    5622     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
    5623     * </pre>
    5624     *
    5625     * @param str The string.
    5626     * @param prefix The prefix to prepend to the start of the string.
    5627     * @param prefixes Additional prefixes that are valid (optional).
    5628     * @return A new String if prefix was prepended, the same string otherwise.
    5629     * @since 3.2
    5630     * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
    5631     *             CharSequence...)}
    5632     */
    5633    @Deprecated
    5634    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5635        return Strings.CI.prependIfMissing(str, prefix, prefixes);
    5636    }
    5637
    5638    /**
    5639     * Removes all occurrences of a character from within the source string.
    5640     *
    5641     * <p>A {@code null} source string will return {@code null}.
    5642     * An empty ("") source string will return the empty string.</p>
    5643     *
    5644     * <pre>
    5645     * StringUtils.remove(null, *)       = null
    5646     * StringUtils.remove("", *)         = ""
    5647     * StringUtils.remove("queued", 'u') = "qeed"
    5648     * StringUtils.remove("queued", 'z') = "queued"
    5649     * </pre>
    5650     *
    5651     * @param str  the source String to search, may be null
    5652     * @param remove  the char to search for and remove, may be null
    5653     * @return the substring with the char removed if found,
    5654     *  {@code null} if null String input
    5655     * @since 2.1
    5656     */
    5657    public static String remove(final String str, final char remove) {
    5658        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    5659            return str;
    5660        }
    5661        final char[] chars = str.toCharArray();
    5662        int pos = 0;
    5663        for (int i = 0; i < chars.length; i++) {
    5664            if (chars[i] != remove) {
    5665                chars[pos++] = chars[i];
    5666            }
    5667        }
    5668        return new String(chars, 0, pos);
    5669    }
    5670
    5671    /**
    5672     * Removes all occurrences of a substring from within the source string.
    5673     *
    5674     * <p>A {@code null} source string will return {@code null}.
    5675     * An empty ("") source string will return the empty string.
    5676     * A {@code null} remove string will return the source string.
    5677     * An empty ("") remove string will return the source string.</p>
    5678     *
    5679     * <pre>
    5680     * StringUtils.remove(null, *)        = null
    5681     * StringUtils.remove("", *)          = ""
    5682     * StringUtils.remove(*, null)        = *
    5683     * StringUtils.remove(*, "")          = *
    5684     * StringUtils.remove("queued", "ue") = "qd"
    5685     * StringUtils.remove("queued", "zz") = "queued"
    5686     * </pre>
    5687     *
    5688     * @param str  the source String to search, may be null
    5689     * @param remove  the String to search for and remove, may be null
    5690     * @return the substring with the string removed if found,
    5691     *  {@code null} if null String input
    5692     * @since 2.1
    5693     * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}
    5694     */
    5695    @Deprecated
    5696    public static String remove(final String str, final String remove) {
    5697        return Strings.CS.remove(str, remove);
    5698    }
    5699
    5700    /**
    5701     * Removes each substring of the text String that matches the given regular expression.
    5702     *
    5703     * This method is a {@code null} safe equivalent to:
    5704     * <ul>
    5705     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
    5706     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
    5707     * </ul>
    5708     *
    5709     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5710     *
    5711     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
    5712     * is NOT automatically added.
    5713     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    5714     * DOTALL is also known as single-line mode in Perl.</p>
    5715     *
    5716     * <pre>{@code
    5717     * StringUtils.removeAll(null, *)      = null
    5718     * StringUtils.removeAll("any", (String) null)  = "any"
    5719     * StringUtils.removeAll("any", "")    = "any"
    5720     * StringUtils.removeAll("any", ".*")  = ""
    5721     * StringUtils.removeAll("any", ".+")  = ""
    5722     * StringUtils.removeAll("abc", ".?")  = ""
    5723     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
    5724     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
    5725     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
    5726     * }</pre>
    5727     *
    5728     * @param text  text to remove from, may be null
    5729     * @param regex  the regular expression to which this string is to be matched
    5730     * @return  the text with any removes processed,
    5731     *              {@code null} if null String input
    5732     *
    5733     * @throws  java.util.regex.PatternSyntaxException
    5734     *              if the regular expression's syntax is invalid
    5735     *
    5736     * @see #replaceAll(String, String, String)
    5737     * @see #removePattern(String, String)
    5738     * @see String#replaceAll(String, String)
    5739     * @see java.util.regex.Pattern
    5740     * @see java.util.regex.Pattern#DOTALL
    5741     * @since 3.5
    5742     * @deprecated Moved to RegExUtils.
    5743     */
    5744    @Deprecated
    5745    public static String removeAll(final String text, final String regex) {
    5746        return RegExUtils.removeAll(text, regex);
    5747    }
    5748
    5749    /**
    5750     * Removes a substring only if it is at the end of a source string,
    5751     * otherwise returns the source string.
    5752     *
    5753     * <p>A {@code null} source string will return {@code null}.
    5754     * An empty ("") source string will return the empty string.
    5755     * A {@code null} search string will return the source string.</p>
    5756     *
    5757     * <pre>
    5758     * StringUtils.removeEnd(null, *)      = null
    5759     * StringUtils.removeEnd("", *)        = ""
    5760     * StringUtils.removeEnd(*, null)      = *
    5761     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    5762     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    5763     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    5764     * StringUtils.removeEnd("abc", "")    = "abc"
    5765     * </pre>
    5766     *
    5767     * @param str  the source String to search, may be null
    5768     * @param remove  the String to search for and remove, may be null
    5769     * @return the substring with the string removed if found,
    5770     *  {@code null} if null String input
    5771     * @since 2.1
    5772     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}
    5773     */
    5774    @Deprecated
    5775    public static String removeEnd(final String str, final String remove) {
    5776        return Strings.CS.removeEnd(str, remove);
    5777    }
    5778
    5779    /**
    5780     * Case-insensitive removal of a substring if it is at the end of a source string,
    5781     * otherwise returns the source string.
    5782     *
    5783     * <p>A {@code null} source string will return {@code null}.
    5784     * An empty ("") source string will return the empty string.
    5785     * A {@code null} search string will return the source string.</p>
    5786     *
    5787     * <pre>
    5788     * StringUtils.removeEndIgnoreCase(null, *)      = null
    5789     * StringUtils.removeEndIgnoreCase("", *)        = ""
    5790     * StringUtils.removeEndIgnoreCase(*, null)      = *
    5791     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    5792     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    5793     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    5794     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    5795     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    5796     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    5797     * </pre>
    5798     *
    5799     * @param str  the source String to search, may be null
    5800     * @param remove  the String to search for (case-insensitive) and remove, may be null
    5801     * @return the substring with the string removed if found,
    5802     *  {@code null} if null String input
    5803     * @since 2.4
    5804     * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}
    5805     */
    5806    @Deprecated
    5807    public static String removeEndIgnoreCase(final String str, final String remove) {
    5808        return Strings.CI.removeEnd(str, remove);
    5809    }
    5810
    5811    /**
    5812     * Removes the first substring of the text string that matches the given regular expression.
    5813     *
    5814     * This method is a {@code null} safe equivalent to:
    5815     * <ul>
    5816     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
    5817     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
    5818     * </ul>
    5819     *
    5820     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5821     *
    5822     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    5823     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    5824     * DOTALL is also known as single-line mode in Perl.</p>
    5825     *
    5826     * <pre>{@code
    5827     * StringUtils.removeFirst(null, *)      = null
    5828     * StringUtils.removeFirst("any", (String) null)  = "any"
    5829     * StringUtils.removeFirst("any", "")    = "any"
    5830     * StringUtils.removeFirst("any", ".*")  = ""
    5831     * StringUtils.removeFirst("any", ".+")  = ""
    5832     * StringUtils.removeFirst("abc", ".?")  = "bc"
    5833     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
    5834     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
    5835     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
    5836     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
    5837     * }</pre>
    5838     *
    5839     * @param text  text to remove from, may be null
    5840     * @param regex  the regular expression to which this string is to be matched
    5841     * @return  the text with the first replacement processed,
    5842     *              {@code null} if null String input
    5843     *
    5844     * @throws  java.util.regex.PatternSyntaxException
    5845     *              if the regular expression's syntax is invalid
    5846     *
    5847     * @see #replaceFirst(String, String, String)
    5848     * @see String#replaceFirst(String, String)
    5849     * @see java.util.regex.Pattern
    5850     * @see java.util.regex.Pattern#DOTALL
    5851     * @since 3.5
    5852     * @deprecated Moved to RegExUtils.
    5853     */
    5854    @Deprecated
    5855    public static String removeFirst(final String text, final String regex) {
    5856        return replaceFirst(text, regex, EMPTY);
    5857    }
    5858
    5859    /**
    5860     * Case-insensitive removal of all occurrences of a substring from within
    5861     * the source string.
    5862     *
    5863     * <p>
    5864     * A {@code null} source string will return {@code null}. An empty ("")
    5865     * source string will return the empty string. A {@code null} remove string
    5866     * will return the source string. An empty ("") remove string will return
    5867     * the source string.
    5868     * </p>
    5869     *
    5870     * <pre>
    5871     * StringUtils.removeIgnoreCase(null, *)        = null
    5872     * StringUtils.removeIgnoreCase("", *)          = ""
    5873     * StringUtils.removeIgnoreCase(*, null)        = *
    5874     * StringUtils.removeIgnoreCase(*, "")          = *
    5875     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
    5876     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
    5877     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
    5878     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
    5879     * </pre>
    5880     *
    5881     * @param str
    5882     *            the source String to search, may be null
    5883     * @param remove
    5884     *            the String to search for (case-insensitive) and remove, may be
    5885     *            null
    5886     * @return the substring with the string removed if found, {@code null} if
    5887     *         null String input
    5888     * @since 3.5
    5889     * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}
    5890     */
    5891    @Deprecated
    5892    public static String removeIgnoreCase(final String str, final String remove) {
    5893        return Strings.CI.remove(str, remove);
    5894    }
    5895
    5896    /**
    5897     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
    5898     *
    5899     * This call is a {@code null} safe equivalent to:
    5900     * <ul>
    5901     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
    5902     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
    5903     * </ul>
    5904     *
    5905     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5906     *
    5907     * <pre>{@code
    5908     * StringUtils.removePattern(null, *)       = null
    5909     * StringUtils.removePattern("any", (String) null)   = "any"
    5910     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
    5911     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
    5912     * }</pre>
    5913     *
    5914     * @param source
    5915     *            the source string
    5916     * @param regex
    5917     *            the regular expression to which this string is to be matched
    5918     * @return The resulting {@link String}
    5919     * @see #replacePattern(String, String, String)
    5920     * @see String#replaceAll(String, String)
    5921     * @see Pattern#DOTALL
    5922     * @since 3.2
    5923     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    5924     * @deprecated Moved to RegExUtils.
    5925     */
    5926    @Deprecated
    5927    public static String removePattern(final String source, final String regex) {
    5928        return RegExUtils.removePattern(source, regex);
    5929    }
    5930
    5931    /**
    5932     * Removes a char only if it is at the beginning of a source string,
    5933     * otherwise returns the source string.
    5934     *
    5935     * <p>A {@code null} source string will return {@code null}.
    5936     * An empty ("") source string will return the empty string.
    5937     * A {@code null} search char will return the source string.</p>
    5938     *
    5939     * <pre>
    5940     * StringUtils.removeStart(null, *)      = null
    5941     * StringUtils.removeStart("", *)        = ""
    5942     * StringUtils.removeStart(*, null)      = *
    5943     * StringUtils.removeStart("/path", '/') = "path"
    5944     * StringUtils.removeStart("path", '/')  = "path"
    5945     * StringUtils.removeStart("path", 0)    = "path"
    5946     * </pre>
    5947     *
    5948     * @param str  the source String to search, may be null.
    5949     * @param remove  the char to search for and remove.
    5950     * @return the substring with the char removed if found,
    5951     *  {@code null} if null String input.
    5952     * @since 3.13.0
    5953     */
    5954    public static String removeStart(final String str, final char remove) {
    5955        if (isEmpty(str)) {
    5956            return str;
    5957        }
    5958        return str.charAt(0) == remove ? str.substring(1) : str;
    5959    }
    5960
    5961    /**
    5962     * Removes a substring only if it is at the beginning of a source string,
    5963     * otherwise returns the source string.
    5964     *
    5965     * <p>A {@code null} source string will return {@code null}.
    5966     * An empty ("") source string will return the empty string.
    5967     * A {@code null} search string will return the source string.</p>
    5968     *
    5969     * <pre>
    5970     * StringUtils.removeStart(null, *)      = null
    5971     * StringUtils.removeStart("", *)        = ""
    5972     * StringUtils.removeStart(*, null)      = *
    5973     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    5974     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    5975     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    5976     * StringUtils.removeStart("abc", "")    = "abc"
    5977     * </pre>
    5978     *
    5979     * @param str  the source String to search, may be null
    5980     * @param remove  the String to search for and remove, may be null
    5981     * @return the substring with the string removed if found,
    5982     *  {@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,
    5993     * otherwise returns the source string.
    5994     *
    5995     * <p>A {@code null} source string will return {@code null}.
    5996     * An empty ("") source string will return the empty string.
    5997     * A {@code null} search string will return the source string.</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,
    6013     *  {@code null} if null String input
    6014     * @since 2.4
    6015     * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}
    6016     */
    6017    @Deprecated
    6018    public static String removeStartIgnoreCase(final String str, final String remove) {
    6019        return Strings.CI.removeStart(str, remove);
    6020    }
    6021
    6022    /**
    6023     * Returns padding using the specified delimiter repeated
    6024     * to a given length.
    6025     *
    6026     * <pre>
    6027     * StringUtils.repeat('e', 0)  = ""
    6028     * StringUtils.repeat('e', 3)  = "eee"
    6029     * StringUtils.repeat('e', -2) = ""
    6030     * </pre>
    6031     *
    6032     * <p>Note: this method does not support padding with
    6033     * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    6034     * as they require a pair of {@code char}s to be represented.
    6035     * If you are needing to support full I18N of your applications
    6036     * consider using {@link #repeat(String, int)} instead.
    6037     * </p>
    6038     *
    6039     * @param repeat  character to repeat
    6040     * @param count  number of times to repeat char, negative treated as zero
    6041     * @return String with repeated character
    6042     * @see #repeat(String, int)
    6043     */
    6044    public static String repeat(final char repeat, final int count) {
    6045        if (count <= 0) {
    6046            return EMPTY;
    6047        }
    6048        return new String(ArrayFill.fill(new char[count], repeat));
    6049    }
    6050
    6051    /**
    6052     * Repeats a String {@code repeat} times to form a
    6053     * new String.
    6054     *
    6055     * <pre>
    6056     * StringUtils.repeat(null, 2) = null
    6057     * StringUtils.repeat("", 0)   = ""
    6058     * StringUtils.repeat("", 2)   = ""
    6059     * StringUtils.repeat("a", 3)  = "aaa"
    6060     * StringUtils.repeat("ab", 2) = "abab"
    6061     * StringUtils.repeat("a", -2) = ""
    6062     * </pre>
    6063     *
    6064     * @param repeat  the String to repeat, may be null
    6065     * @param count  number of times to repeat str, negative treated as zero
    6066     * @return a new String consisting of the original String repeated,
    6067     *  {@code null} if null String input
    6068     */
    6069    public static String repeat(final String repeat, final int count) {
    6070        // Performance tuned for 2.0 (JDK1.4)
    6071        if (repeat == null) {
    6072            return null;
    6073        }
    6074        if (count <= 0) {
    6075            return EMPTY;
    6076        }
    6077        final int inputLength = repeat.length();
    6078        if (count == 1 || inputLength == 0) {
    6079            return repeat;
    6080        }
    6081        if (inputLength == 1 && count <= PAD_LIMIT) {
    6082            return repeat(repeat.charAt(0), count);
    6083        }
    6084
    6085        final int outputLength = inputLength * count;
    6086        switch (inputLength) {
    6087            case 1 :
    6088                return repeat(repeat.charAt(0), count);
    6089            case 2 :
    6090                final char ch0 = repeat.charAt(0);
    6091                final char ch1 = repeat.charAt(1);
    6092                final char[] output2 = new char[outputLength];
    6093                for (int i = count * 2 - 2; i >= 0; i--, i--) {
    6094                    output2[i] = ch0;
    6095                    output2[i + 1] = ch1;
    6096                }
    6097                return new String(output2);
    6098            default :
    6099                final StringBuilder buf = new StringBuilder(outputLength);
    6100                for (int i = 0; i < count; i++) {
    6101                    buf.append(repeat);
    6102                }
    6103                return buf.toString();
    6104        }
    6105    }
    6106
    6107    /**
    6108     * Repeats a String {@code repeat} times to form a
    6109     * new String, with a String separator injected each time.
    6110     *
    6111     * <pre>
    6112     * StringUtils.repeat(null, null, 2) = null
    6113     * StringUtils.repeat(null, "x", 2)  = null
    6114     * StringUtils.repeat("", null, 0)   = ""
    6115     * StringUtils.repeat("", "", 2)     = ""
    6116     * StringUtils.repeat("", "x", 3)    = "xx"
    6117     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    6118     * </pre>
    6119     *
    6120     * @param repeat        the String to repeat, may be null
    6121     * @param separator  the String to inject, may be null
    6122     * @param count     number of times to repeat str, negative treated as zero
    6123     * @return a new String consisting of the original String repeated,
    6124     *  {@code null} if null String input
    6125     * @since 2.5
    6126     */
    6127    public static String repeat(final String repeat, final String separator, final int count) {
    6128        if (repeat == null || separator == null) {
    6129            return repeat(repeat, count);
    6130        }
    6131        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    6132        final String result = repeat(repeat + separator, count);
    6133        return Strings.CS.removeEnd(result, separator);
    6134    }
    6135
    6136    /**
    6137     * Replaces all occurrences of a String within another String.
    6138     *
    6139     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6140     *
    6141     * <pre>
    6142     * StringUtils.replace(null, *, *)        = null
    6143     * StringUtils.replace("", *, *)          = ""
    6144     * StringUtils.replace("any", null, *)    = "any"
    6145     * StringUtils.replace("any", *, null)    = "any"
    6146     * StringUtils.replace("any", "", *)      = "any"
    6147     * StringUtils.replace("aba", "a", null)  = "aba"
    6148     * StringUtils.replace("aba", "a", "")    = "b"
    6149     * StringUtils.replace("aba", "a", "z")   = "zbz"
    6150     * </pre>
    6151     *
    6152     * @see #replace(String text, String searchString, String replacement, int max)
    6153     * @param text  text to search and replace in, may be null
    6154     * @param searchString  the String to search for, may be null
    6155     * @param replacement  the String to replace it with, may be null
    6156     * @return the text with any replacements processed,
    6157     *  {@code null} if null String input
    6158     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}
    6159     */
    6160    @Deprecated
    6161    public static String replace(final String text, final String searchString, final String replacement) {
    6162        return Strings.CS.replace(text, searchString, replacement);
    6163    }
    6164
    6165    /**
    6166     * Replaces a String with another String inside a larger String,
    6167     * for the first {@code max} values of the search String.
    6168     *
    6169     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6170     *
    6171     * <pre>
    6172     * StringUtils.replace(null, *, *, *)         = null
    6173     * StringUtils.replace("", *, *, *)           = ""
    6174     * StringUtils.replace("any", null, *, *)     = "any"
    6175     * StringUtils.replace("any", *, null, *)     = "any"
    6176     * StringUtils.replace("any", "", *, *)       = "any"
    6177     * StringUtils.replace("any", *, *, 0)        = "any"
    6178     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    6179     * StringUtils.replace("abaa", "a", "", -1)   = "b"
    6180     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    6181     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    6182     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    6183     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    6184     * </pre>
    6185     *
    6186     * @param text  text to search and replace in, may be null
    6187     * @param searchString  the String to search for, may be null
    6188     * @param replacement  the String to replace it with, may be null
    6189     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6190     * @return the text with any replacements processed,
    6191     *  {@code null} if null String input
    6192     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}
    6193     */
    6194    @Deprecated
    6195    public static String replace(final String text, final String searchString, final String replacement, final int max) {
    6196        return Strings.CS.replace(text, searchString, replacement, max);
    6197    }
    6198
    6199    /**
    6200     * Replaces each substring of the text String that matches the given regular expression
    6201     * with the given replacement.
    6202     *
    6203     * This method is a {@code null} safe equivalent to:
    6204     * <ul>
    6205     *  <li>{@code text.replaceAll(regex, replacement)}</li>
    6206     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
    6207     * </ul>
    6208     *
    6209     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6210     *
    6211     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
    6212     * is NOT automatically added.
    6213     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6214     * DOTALL is also known as single-line mode in Perl.</p>
    6215     *
    6216     * <pre>{@code
    6217     * StringUtils.replaceAll(null, *, *)       = null
    6218     * StringUtils.replaceAll("any", (String) null, *)   = "any"
    6219     * StringUtils.replaceAll("any", *, null)   = "any"
    6220     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
    6221     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
    6222     * StringUtils.replaceAll("", ".+", "zzz")  = ""
    6223     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
    6224     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
    6225     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
    6226     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
    6227     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    6228     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    6229     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6230     * }</pre>
    6231     *
    6232     * @param text  text to search and replace in, may be null
    6233     * @param regex  the regular expression to which this string is to be matched
    6234     * @param replacement  the string to be substituted for each match
    6235     * @return  the text with any replacements processed,
    6236     *              {@code null} if null String input
    6237     *
    6238     * @throws  java.util.regex.PatternSyntaxException
    6239     *              if the regular expression's syntax is invalid
    6240     *
    6241     * @see #replacePattern(String, String, String)
    6242     * @see String#replaceAll(String, String)
    6243     * @see java.util.regex.Pattern
    6244     * @see java.util.regex.Pattern#DOTALL
    6245     * @since 3.5
    6246     * @deprecated Moved to RegExUtils.
    6247     */
    6248    @Deprecated
    6249    public static String replaceAll(final String text, final String regex, final String replacement) {
    6250        return RegExUtils.replaceAll(text, regex, replacement);
    6251    }
    6252
    6253    /**
    6254     * Replaces all occurrences of a character in a String with another.
    6255     * This is a null-safe version of {@link String#replace(char, char)}.
    6256     *
    6257     * <p>A {@code null} string input returns {@code null}.
    6258     * An empty ("") string input returns an empty string.</p>
    6259     *
    6260     * <pre>
    6261     * StringUtils.replaceChars(null, *, *)        = null
    6262     * StringUtils.replaceChars("", *, *)          = ""
    6263     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    6264     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    6265     * </pre>
    6266     *
    6267     * @param str  String to replace characters in, may be null
    6268     * @param searchChar  the character to search for, may be null
    6269     * @param replaceChar  the character to replace, may be null
    6270     * @return modified String, {@code null} if null string input
    6271     * @since 2.0
    6272     */
    6273    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
    6274        if (str == null) {
    6275            return null;
    6276        }
    6277        return str.replace(searchChar, replaceChar);
    6278    }
    6279
    6280    /**
    6281     * Replaces multiple characters in a String in one go.
    6282     * This method can also be used to delete characters.
    6283     *
    6284     * <p>For example:<br>
    6285     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
    6286     *
    6287     * <p>A {@code null} string input returns {@code null}.
    6288     * An empty ("") string input returns an empty string.
    6289     * A null or empty set of search characters returns the input string.</p>
    6290     *
    6291     * <p>The length of the search characters should normally equal the length
    6292     * of the replace characters.
    6293     * If the search characters is longer, then the extra search characters
    6294     * are deleted.
    6295     * If the search characters is shorter, then the extra replace characters
    6296     * are ignored.</p>
    6297     *
    6298     * <pre>
    6299     * StringUtils.replaceChars(null, *, *)           = null
    6300     * StringUtils.replaceChars("", *, *)             = ""
    6301     * StringUtils.replaceChars("abc", null, *)       = "abc"
    6302     * StringUtils.replaceChars("abc", "", *)         = "abc"
    6303     * StringUtils.replaceChars("abc", "b", null)     = "ac"
    6304     * StringUtils.replaceChars("abc", "b", "")       = "ac"
    6305     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    6306     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    6307     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    6308     * </pre>
    6309     *
    6310     * @param str  String to replace characters in, may be null
    6311     * @param searchChars  a set of characters to search for, may be null
    6312     * @param replaceChars  a set of characters to replace, may be null
    6313     * @return modified String, {@code null} if null string input
    6314     * @since 2.0
    6315     */
    6316    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
    6317        if (isEmpty(str) || isEmpty(searchChars)) {
    6318            return str;
    6319        }
    6320        replaceChars = ObjectUtils.toString(replaceChars);
    6321        boolean modified = false;
    6322        final int replaceCharsLength = replaceChars.length();
    6323        final int strLength = str.length();
    6324        final StringBuilder buf = new StringBuilder(strLength);
    6325        for (int i = 0; i < strLength; i++) {
    6326            final char ch = str.charAt(i);
    6327            final int index = searchChars.indexOf(ch);
    6328            if (index >= 0) {
    6329                modified = true;
    6330                if (index < replaceCharsLength) {
    6331                    buf.append(replaceChars.charAt(index));
    6332                }
    6333            } else {
    6334                buf.append(ch);
    6335            }
    6336        }
    6337        if (modified) {
    6338            return buf.toString();
    6339        }
    6340        return str;
    6341    }
    6342
    6343    /**
    6344     * Replaces all occurrences of Strings within another String.
    6345     *
    6346     * <p>
    6347     * A {@code null} reference passed to this method is a no-op, or if
    6348     * any "search string" or "string to replace" is null, that replace will be
    6349     * ignored. This will not repeat. For repeating replaces, call the
    6350     * overloaded method.
    6351     * </p>
    6352     *
    6353     * <pre>
    6354     *  StringUtils.replaceEach(null, *, *)        = null
    6355     *  StringUtils.replaceEach("", *, *)          = ""
    6356     *  StringUtils.replaceEach("aba", null, null) = "aba"
    6357     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
    6358     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
    6359     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
    6360     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
    6361     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
    6362     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    6363     *  (example of how it does not repeat)
    6364     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    6365     * </pre>
    6366     *
    6367     * @param text
    6368     *            text to search and replace in, no-op if null
    6369     * @param searchList
    6370     *            the Strings to search for, no-op if null
    6371     * @param replacementList
    6372     *            the Strings to replace them with, no-op if null
    6373     * @return the text with any replacements processed, {@code null} if
    6374     *         null String input
    6375     * @throws IllegalArgumentException
    6376     *             if the lengths of the arrays are not the same (null is ok,
    6377     *             and/or size 0)
    6378     * @since 2.4
    6379     */
    6380    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
    6381        return replaceEach(text, searchList, replacementList, false, 0);
    6382    }
    6383
    6384    /**
    6385     * Replace all occurrences of Strings within another String.
    6386     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
    6387     * {@link #replaceEach(String, String[], String[])}
    6388     *
    6389     * <p>
    6390     * A {@code null} reference passed to this method is a no-op, or if
    6391     * any "search string" or "string to replace" is null, that replace will be
    6392     * ignored.
    6393     * </p>
    6394     *
    6395     * <pre>
    6396     *  StringUtils.replaceEach(null, *, *, *, *) = null
    6397     *  StringUtils.replaceEach("", *, *, *, *) = ""
    6398     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
    6399     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
    6400     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
    6401     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
    6402     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
    6403     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
    6404     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
    6405     *  (example of how it repeats)
    6406     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
    6407     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
    6408     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
    6409     * </pre>
    6410     *
    6411     * @param text
    6412     *            text to search and replace in, no-op if null
    6413     * @param searchList
    6414     *            the Strings to search for, no-op if null
    6415     * @param replacementList
    6416     *            the Strings to replace them with, no-op if null
    6417     * @param repeat if true, then replace repeatedly
    6418     *       until there are no more possible replacements or timeToLive < 0
    6419     * @param timeToLive
    6420     *            if less than 0 then there is a circular reference and endless
    6421     *            loop
    6422     * @return the text with any replacements processed, {@code null} if
    6423     *         null String input
    6424     * @throws IllegalStateException
    6425     *             if the search is repeating and there is an endless loop due
    6426     *             to outputs of one being inputs to another
    6427     * @throws IllegalArgumentException
    6428     *             if the lengths of the arrays are not the same (null is ok,
    6429     *             and/or size 0)
    6430     * @since 2.4
    6431     */
    6432    private static String replaceEach(
    6433            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
    6434
    6435        // mchyzer Performance note: This creates very few new objects (one major goal)
    6436        // let me know if there are performance requests, we can create a harness to measure
    6437        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
    6438            return text;
    6439        }
    6440
    6441        // if recursing, this shouldn't be less than 0
    6442        if (timeToLive < 0) {
    6443            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
    6444                "output of one loop is the input of another");
    6445        }
    6446
    6447        final int searchLength = searchList.length;
    6448        final int replacementLength = replacementList.length;
    6449
    6450        // make sure lengths are ok, these need to be equal
    6451        if (searchLength != replacementLength) {
    6452            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    6453                + searchLength
    6454                + " vs "
    6455                + replacementLength);
    6456        }
    6457
    6458        // keep track of which still have matches
    6459        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    6460
    6461        // index on index that the match was found
    6462        int textIndex = -1;
    6463        int replaceIndex = -1;
    6464        int tempIndex;
    6465
    6466        // index of replace array that will replace the search string found
    6467        // NOTE: logic duplicated below START
    6468        for (int i = 0; i < searchLength; i++) {
    6469            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6470                continue;
    6471            }
    6472            tempIndex = text.indexOf(searchList[i]);
    6473
    6474            // see if we need to keep searching for this
    6475            if (tempIndex == -1) {
    6476                noMoreMatchesForReplIndex[i] = true;
    6477            } else if (textIndex == -1 || tempIndex < textIndex) {
    6478                textIndex = tempIndex;
    6479                replaceIndex = i;
    6480            }
    6481        }
    6482        // NOTE: logic mostly below END
    6483
    6484        // no search strings found, we are done
    6485        if (textIndex == -1) {
    6486            return text;
    6487        }
    6488
    6489        int start = 0;
    6490
    6491        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
    6492        int increase = 0;
    6493
    6494        // count the replacement text elements that are larger than their corresponding text being replaced
    6495        for (int i = 0; i < searchList.length; i++) {
    6496            if (searchList[i] == null || replacementList[i] == null) {
    6497                continue;
    6498            }
    6499            final int greater = replacementList[i].length() - searchList[i].length();
    6500            if (greater > 0) {
    6501                increase += 3 * greater; // assume 3 matches
    6502            }
    6503        }
    6504        // have upper-bound at 20% increase, then let Java take over
    6505        increase = Math.min(increase, text.length() / 5);
    6506
    6507        final StringBuilder buf = new StringBuilder(text.length() + increase);
    6508
    6509        while (textIndex != -1) {
    6510
    6511            for (int i = start; i < textIndex; i++) {
    6512                buf.append(text.charAt(i));
    6513            }
    6514            buf.append(replacementList[replaceIndex]);
    6515
    6516            start = textIndex + searchList[replaceIndex].length();
    6517
    6518            textIndex = -1;
    6519            replaceIndex = -1;
    6520            // find the next earliest match
    6521            // NOTE: logic mostly duplicated above START
    6522            for (int i = 0; i < searchLength; i++) {
    6523                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6524                    continue;
    6525                }
    6526                tempIndex = text.indexOf(searchList[i], start);
    6527
    6528                // see if we need to keep searching for this
    6529                if (tempIndex == -1) {
    6530                    noMoreMatchesForReplIndex[i] = true;
    6531                } else if (textIndex == -1 || tempIndex < textIndex) {
    6532                    textIndex = tempIndex;
    6533                    replaceIndex = i;
    6534                }
    6535            }
    6536            // NOTE: logic duplicated above END
    6537
    6538        }
    6539        final int textLength = text.length();
    6540        for (int i = start; i < textLength; i++) {
    6541            buf.append(text.charAt(i));
    6542        }
    6543        final String result = buf.toString();
    6544        if (!repeat) {
    6545            return result;
    6546        }
    6547
    6548        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    6549    }
    6550
    6551    /**
    6552     * Replaces all occurrences of Strings within another String.
    6553     *
    6554     * <p>
    6555     * A {@code null} reference passed to this method is a no-op, or if
    6556     * any "search string" or "string to replace" is null, that replace will be
    6557     * ignored.
    6558     * </p>
    6559     *
    6560     * <pre>
    6561     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
    6562     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
    6563     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
    6564     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
    6565     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
    6566     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
    6567     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
    6568     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
    6569     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
    6570     *  (example of how it repeats)
    6571     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
    6572     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
    6573     * </pre>
    6574     *
    6575     * @param text
    6576     *            text to search and replace in, no-op if null
    6577     * @param searchList
    6578     *            the Strings to search for, no-op if null
    6579     * @param replacementList
    6580     *            the Strings to replace them with, no-op if null
    6581     * @return the text with any replacements processed, {@code null} if
    6582     *         null String input
    6583     * @throws IllegalStateException
    6584     *             if the search is repeating and there is an endless loop due
    6585     *             to outputs of one being inputs to another
    6586     * @throws IllegalArgumentException
    6587     *             if the lengths of the arrays are not the same (null is ok,
    6588     *             and/or size 0)
    6589     * @since 2.4
    6590     */
    6591    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
    6592        final int timeToLive = Math.max(ArrayUtils.getLength(searchList), DEFAULT_TTL);
    6593        return replaceEach(text, searchList, replacementList, true, timeToLive);
    6594    }
    6595
    6596    /**
    6597     * Replaces the first substring of the text string that matches the given regular expression
    6598     * with the given replacement.
    6599     *
    6600     * This method is a {@code null} safe equivalent to:
    6601     * <ul>
    6602     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
    6603     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
    6604     * </ul>
    6605     *
    6606     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6607     *
    6608     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    6609     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6610     * DOTALL is also known as single-line mode in Perl.</p>
    6611     *
    6612     * <pre>{@code
    6613     * StringUtils.replaceFirst(null, *, *)       = null
    6614     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
    6615     * StringUtils.replaceFirst("any", *, null)   = "any"
    6616     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
    6617     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
    6618     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
    6619     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
    6620     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
    6621     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
    6622     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
    6623     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
    6624     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
    6625     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
    6626     * }</pre>
    6627     *
    6628     * @param text  text to search and replace in, may be null
    6629     * @param regex  the regular expression to which this string is to be matched
    6630     * @param replacement  the string to be substituted for the first match
    6631     * @return  the text with the first replacement processed,
    6632     *              {@code null} if null String input
    6633     *
    6634     * @throws  java.util.regex.PatternSyntaxException
    6635     *              if the regular expression's syntax is invalid
    6636     *
    6637     * @see String#replaceFirst(String, String)
    6638     * @see java.util.regex.Pattern
    6639     * @see java.util.regex.Pattern#DOTALL
    6640     * @since 3.5
    6641     * @deprecated Moved to RegExUtils.
    6642     */
    6643    @Deprecated
    6644    public static String replaceFirst(final String text, final String regex, final String replacement) {
    6645        return RegExUtils.replaceFirst(text, regex, replacement);
    6646    }
    6647
    6648    /**
    6649     * Case insensitively replaces all occurrences of a String within another String.
    6650     *
    6651     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6652     *
    6653     * <pre>
    6654     * StringUtils.replaceIgnoreCase(null, *, *)        = null
    6655     * StringUtils.replaceIgnoreCase("", *, *)          = ""
    6656     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
    6657     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
    6658     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
    6659     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
    6660     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
    6661     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
    6662     * </pre>
    6663     *
    6664     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6665     * @param text  text to search and replace in, may be null
    6666     * @param searchString  the String to search for (case-insensitive), may be null
    6667     * @param replacement  the String to replace it with, may be null
    6668     * @return the text with any replacements processed,
    6669     *  {@code null} if null String input
    6670     * @since 3.5
    6671     * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}
    6672     */
    6673    @Deprecated
    6674     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
    6675         return Strings.CI.replace(text, searchString, replacement);
    6676     }
    6677
    6678    /**
    6679     * Case insensitively replaces a String with another String inside a larger String,
    6680     * for the first {@code max} values of the search String.
    6681     *
    6682     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6683     *
    6684     * <pre>
    6685     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
    6686     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
    6687     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
    6688     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
    6689     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
    6690     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
    6691     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
    6692     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
    6693     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
    6694     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
    6695     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
    6696     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
    6697     * </pre>
    6698     *
    6699     * @param text  text to search and replace in, may be null
    6700     * @param searchString  the String to search for (case-insensitive), may be null
    6701     * @param replacement  the String to replace it with, may be null
    6702     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6703     * @return the text with any replacements processed,
    6704     *  {@code null} if null String input
    6705     * @since 3.5
    6706     * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}
    6707     */
    6708    @Deprecated
    6709    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
    6710        return Strings.CI.replace(text, searchString, replacement, max);
    6711    }
    6712
    6713    /**
    6714     * Replaces a String with another String inside a larger String, once.
    6715     *
    6716     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6717     *
    6718     * <pre>
    6719     * StringUtils.replaceOnce(null, *, *)        = null
    6720     * StringUtils.replaceOnce("", *, *)          = ""
    6721     * StringUtils.replaceOnce("any", null, *)    = "any"
    6722     * StringUtils.replaceOnce("any", *, null)    = "any"
    6723     * StringUtils.replaceOnce("any", "", *)      = "any"
    6724     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    6725     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    6726     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    6727     * </pre>
    6728     *
    6729     * @see #replace(String text, String searchString, String replacement, int max)
    6730     * @param text  text to search and replace in, may be null
    6731     * @param searchString  the String to search for, may be null
    6732     * @param replacement  the String to replace with, may be null
    6733     * @return the text with any replacements processed,
    6734     *  {@code null} if null String input
    6735     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}
    6736     */
    6737    @Deprecated
    6738    public static String replaceOnce(final String text, final String searchString, final String replacement) {
    6739        return Strings.CS.replaceOnce(text, searchString, replacement);
    6740    }
    6741
    6742    /**
    6743     * Case insensitively replaces a String with another String inside a larger String, once.
    6744     *
    6745     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6746     *
    6747     * <pre>
    6748     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
    6749     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
    6750     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
    6751     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
    6752     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
    6753     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
    6754     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
    6755     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
    6756     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
    6757     * </pre>
    6758     *
    6759     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6760     * @param text  text to search and replace in, may be null
    6761     * @param searchString  the String to search for (case-insensitive), may be null
    6762     * @param replacement  the String to replace with, may be null
    6763     * @return the text with any replacements processed,
    6764     *  {@code null} if null String input
    6765     * @since 3.5
    6766     * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}
    6767     */
    6768    @Deprecated
    6769    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
    6770        return Strings.CI.replaceOnce(text, searchString, replacement);
    6771    }
    6772
    6773    /**
    6774     * Replaces each substring of the source String that matches the given regular expression with the given
    6775     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
    6776     *
    6777     * This call is a {@code null} safe equivalent to:
    6778     * <ul>
    6779     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
    6780     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
    6781     * </ul>
    6782     *
    6783     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6784     *
    6785     * <pre>{@code
    6786     * StringUtils.replacePattern(null, *, *)       = null
    6787     * StringUtils.replacePattern("any", (String) null, *)   = "any"
    6788     * StringUtils.replacePattern("any", *, null)   = "any"
    6789     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
    6790     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
    6791     * StringUtils.replacePattern("", ".+", "zzz")  = ""
    6792     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
    6793     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
    6794     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    6795     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    6796     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6797     * }</pre>
    6798     *
    6799     * @param source
    6800     *            the source string
    6801     * @param regex
    6802     *            the regular expression to which this string is to be matched
    6803     * @param replacement
    6804     *            the string to be substituted for each match
    6805     * @return The resulting {@link String}
    6806     * @see #replaceAll(String, String, String)
    6807     * @see String#replaceAll(String, String)
    6808     * @see Pattern#DOTALL
    6809     * @since 3.2
    6810     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    6811     * @deprecated Moved to RegExUtils.
    6812     */
    6813    @Deprecated
    6814    public static String replacePattern(final String source, final String regex, final String replacement) {
    6815        return RegExUtils.replacePattern(source, regex, replacement);
    6816    }
    6817
    6818    /**
    6819     * Reverses a String as per {@link StringBuilder#reverse()}.
    6820     *
    6821     * <p>A {@code null} String returns {@code null}.</p>
    6822     *
    6823     * <pre>
    6824     * StringUtils.reverse(null)  = null
    6825     * StringUtils.reverse("")    = ""
    6826     * StringUtils.reverse("bat") = "tab"
    6827     * </pre>
    6828     *
    6829     * @param str  the String to reverse, may be null
    6830     * @return the reversed String, {@code null} if null String input
    6831     */
    6832    public static String reverse(final String str) {
    6833        if (str == null) {
    6834            return null;
    6835        }
    6836        return new StringBuilder(str).reverse().toString();
    6837    }
    6838
    6839    /**
    6840     * Reverses a String that is delimited by a specific character.
    6841     *
    6842     * <p>The Strings between the delimiters are not reversed.
    6843     * Thus java.lang.String becomes String.lang.java (if the delimiter
    6844     * is {@code '.'}).</p>
    6845     *
    6846     * <pre>
    6847     * StringUtils.reverseDelimited(null, *)      = null
    6848     * StringUtils.reverseDelimited("", *)        = ""
    6849     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    6850     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    6851     * </pre>
    6852     *
    6853     * @param str  the String to reverse, may be null
    6854     * @param separatorChar  the separator character to use
    6855     * @return the reversed String, {@code null} if null String input
    6856     * @since 2.0
    6857     */
    6858    public static String reverseDelimited(final String str, final char separatorChar) {
    6859        final String[] strs = split(str, separatorChar);
    6860        ArrayUtils.reverse(strs);
    6861        return join(strs, separatorChar);
    6862    }
    6863
    6864    /**
    6865     * Gets the rightmost {@code len} characters of a String.
    6866     *
    6867     * <p>If {@code len} characters are not available, or the String
    6868     * is {@code null}, the String will be returned without an
    6869     * an exception. An empty String is returned if len is negative.</p>
    6870     *
    6871     * <pre>
    6872     * StringUtils.right(null, *)    = null
    6873     * StringUtils.right(*, -ve)     = ""
    6874     * StringUtils.right("", *)      = ""
    6875     * StringUtils.right("abc", 0)   = ""
    6876     * StringUtils.right("abc", 2)   = "bc"
    6877     * StringUtils.right("abc", 4)   = "abc"
    6878     * </pre>
    6879     *
    6880     * @param str  the String to get the rightmost characters from, may be null
    6881     * @param len  the length of the required String
    6882     * @return the rightmost characters, {@code null} if null String input
    6883     */
    6884    public static String right(final String str, final int len) {
    6885        if (str == null) {
    6886            return null;
    6887        }
    6888        if (len < 0) {
    6889            return EMPTY;
    6890        }
    6891        if (str.length() <= len) {
    6892            return str;
    6893        }
    6894        return str.substring(str.length() - len);
    6895    }
    6896
    6897    /**
    6898     * Right pad a String with spaces (' ').
    6899     *
    6900     * <p>The String is padded to the size of {@code size}.</p>
    6901     *
    6902     * <pre>
    6903     * StringUtils.rightPad(null, *)   = null
    6904     * StringUtils.rightPad("", 3)     = "   "
    6905     * StringUtils.rightPad("bat", 3)  = "bat"
    6906     * StringUtils.rightPad("bat", 5)  = "bat  "
    6907     * StringUtils.rightPad("bat", 1)  = "bat"
    6908     * StringUtils.rightPad("bat", -1) = "bat"
    6909     * </pre>
    6910     *
    6911     * @param str  the String to pad out, may be null
    6912     * @param size  the size to pad to
    6913     * @return right padded String or original String if no padding is necessary,
    6914     *  {@code null} if null String input
    6915     */
    6916    public static String rightPad(final String str, final int size) {
    6917        return rightPad(str, size, ' ');
    6918    }
    6919
    6920    /**
    6921     * Right pad a String with a specified character.
    6922     *
    6923     * <p>The String is padded to the size of {@code size}.</p>
    6924     *
    6925     * <pre>
    6926     * StringUtils.rightPad(null, *, *)     = null
    6927     * StringUtils.rightPad("", 3, 'z')     = "zzz"
    6928     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    6929     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    6930     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    6931     * StringUtils.rightPad("bat", -1, 'z') = "bat"
    6932     * </pre>
    6933     *
    6934     * @param str  the String to pad out, may be null
    6935     * @param size  the size to pad to
    6936     * @param padChar  the character to pad with
    6937     * @return right padded String or original String if no padding is necessary,
    6938     *  {@code null} if null String input
    6939     * @since 2.0
    6940     */
    6941    public static String rightPad(final String str, final int size, final char padChar) {
    6942        if (str == null) {
    6943            return null;
    6944        }
    6945        final int pads = size - str.length();
    6946        if (pads <= 0) {
    6947            return str; // returns original String when possible
    6948        }
    6949        if (pads > PAD_LIMIT) {
    6950            return rightPad(str, size, String.valueOf(padChar));
    6951        }
    6952        return str.concat(repeat(padChar, pads));
    6953    }
    6954
    6955    /**
    6956     * Right pad a String with a specified String.
    6957     *
    6958     * <p>The String is padded to the size of {@code size}.</p>
    6959     *
    6960     * <pre>
    6961     * StringUtils.rightPad(null, *, *)      = null
    6962     * StringUtils.rightPad("", 3, "z")      = "zzz"
    6963     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    6964     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    6965     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    6966     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    6967     * StringUtils.rightPad("bat", -1, "yz") = "bat"
    6968     * StringUtils.rightPad("bat", 5, null)  = "bat  "
    6969     * StringUtils.rightPad("bat", 5, "")    = "bat  "
    6970     * </pre>
    6971     *
    6972     * @param str  the String to pad out, may be null
    6973     * @param size  the size to pad to
    6974     * @param padStr  the String to pad with, null or empty treated as single space
    6975     * @return right padded String or original String if no padding is necessary,
    6976     *  {@code null} if null String input
    6977     */
    6978    public static String rightPad(final String str, final int size, String padStr) {
    6979        if (str == null) {
    6980            return null;
    6981        }
    6982        if (isEmpty(padStr)) {
    6983            padStr = SPACE;
    6984        }
    6985        final int padLen = padStr.length();
    6986        final int strLen = str.length();
    6987        final int pads = size - strLen;
    6988        if (pads <= 0) {
    6989            return str; // returns original String when possible
    6990        }
    6991        if (padLen == 1 && pads <= PAD_LIMIT) {
    6992            return rightPad(str, size, padStr.charAt(0));
    6993        }
    6994
    6995        if (pads == padLen) {
    6996            return str.concat(padStr);
    6997        }
    6998        if (pads < padLen) {
    6999            return str.concat(padStr.substring(0, pads));
    7000        }
    7001        final char[] padding = new char[pads];
    7002        final char[] padChars = padStr.toCharArray();
    7003        for (int i = 0; i < pads; i++) {
    7004            padding[i] = padChars[i % padLen];
    7005        }
    7006        return str.concat(new String(padding));
    7007    }
    7008
    7009    /**
    7010     * Rotate (circular shift) a String of {@code shift} characters.
    7011     * <ul>
    7012     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
    7013     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
    7014     * </ul>
    7015     *
    7016     * <pre>
    7017     * StringUtils.rotate(null, *)        = null
    7018     * StringUtils.rotate("", *)          = ""
    7019     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
    7020     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
    7021     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
    7022     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
    7023     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
    7024     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
    7025     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
    7026     * </pre>
    7027     *
    7028     * @param str  the String to rotate, may be null
    7029     * @param shift  number of time to shift (positive : right shift, negative : left shift)
    7030     * @return the rotated String,
    7031     *          or the original String if {@code shift == 0},
    7032     *          or {@code null} if null String input
    7033     * @since 3.5
    7034     */
    7035    public static String rotate(final String str, final int shift) {
    7036        if (str == null) {
    7037            return null;
    7038        }
    7039
    7040        final int strLen = str.length();
    7041        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
    7042            return str;
    7043        }
    7044
    7045        final StringBuilder builder = new StringBuilder(strLen);
    7046        final int offset = - (shift % strLen);
    7047        builder.append(substring(str, offset));
    7048        builder.append(substring(str, 0, offset));
    7049        return builder.toString();
    7050    }
    7051
    7052    /**
    7053     * Splits the provided text into an array, using whitespace as the
    7054     * separator.
    7055     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7056     *
    7057     * <p>The separator is not included in the returned String array.
    7058     * Adjacent separators are treated as one separator.
    7059     * For more control over the split use the StrTokenizer class.</p>
    7060     *
    7061     * <p>A {@code null} input String returns {@code null}.</p>
    7062     *
    7063     * <pre>
    7064     * StringUtils.split(null)       = null
    7065     * StringUtils.split("")         = []
    7066     * StringUtils.split("abc def")  = ["abc", "def"]
    7067     * StringUtils.split("abc  def") = ["abc", "def"]
    7068     * StringUtils.split(" abc ")    = ["abc"]
    7069     * </pre>
    7070     *
    7071     * @param str  the String to parse, may be null
    7072     * @return an array of parsed Strings, {@code null} if null String input
    7073     */
    7074    public static String[] split(final String str) {
    7075        return split(str, null, -1);
    7076    }
    7077
    7078    /**
    7079     * Splits the provided text into an array, separator specified.
    7080     * This is an alternative to using StringTokenizer.
    7081     *
    7082     * <p>The separator is not included in the returned String array.
    7083     * Adjacent separators are treated as one separator.
    7084     * For more control over the split use the StrTokenizer class.</p>
    7085     *
    7086     * <p>A {@code null} input String returns {@code null}.</p>
    7087     *
    7088     * <pre>
    7089     * StringUtils.split(null, *)         = null
    7090     * StringUtils.split("", *)           = []
    7091     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    7092     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    7093     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    7094     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    7095     * </pre>
    7096     *
    7097     * @param str  the String to parse, may be null
    7098     * @param separatorChar  the character used as the delimiter
    7099     * @return an array of parsed Strings, {@code null} if null String input
    7100     * @since 2.0
    7101     */
    7102    public static String[] split(final String str, final char separatorChar) {
    7103        return splitWorker(str, separatorChar, false);
    7104    }
    7105
    7106    /**
    7107     * Splits the provided text into an array, separators specified.
    7108     * This is an alternative to using StringTokenizer.
    7109     *
    7110     * <p>The separator is not included in the returned String array.
    7111     * Adjacent separators are treated as one separator.
    7112     * For more control over the split use the StrTokenizer class.</p>
    7113     *
    7114     * <p>A {@code null} input String returns {@code null}.
    7115     * A {@code null} separatorChars splits on whitespace.</p>
    7116     *
    7117     * <pre>
    7118     * StringUtils.split(null, *)         = null
    7119     * StringUtils.split("", *)           = []
    7120     * StringUtils.split("abc def", null) = ["abc", "def"]
    7121     * StringUtils.split("abc def", " ")  = ["abc", "def"]
    7122     * StringUtils.split("abc  def", " ") = ["abc", "def"]
    7123     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    7124     * </pre>
    7125     *
    7126     * @param str  the String to parse, may be null
    7127     * @param separatorChars  the characters used as the delimiters,
    7128     *  {@code null} splits on whitespace
    7129     * @return an array of parsed Strings, {@code null} if null String input
    7130     */
    7131    public static String[] split(final String str, final String separatorChars) {
    7132        return splitWorker(str, separatorChars, -1, false);
    7133    }
    7134
    7135    /**
    7136     * Splits the provided text into an array with a maximum length,
    7137     * separators specified.
    7138     *
    7139     * <p>The separator is not included in the returned String array.
    7140     * Adjacent separators are treated as one separator.</p>
    7141     *
    7142     * <p>A {@code null} input String returns {@code null}.
    7143     * A {@code null} separatorChars splits on whitespace.</p>
    7144     *
    7145     * <p>If more than {@code max} delimited substrings are found, the last
    7146     * returned string includes all characters after the first {@code max - 1}
    7147     * returned strings (including separator characters).</p>
    7148     *
    7149     * <pre>
    7150     * StringUtils.split(null, *, *)            = null
    7151     * StringUtils.split("", *, *)              = []
    7152     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
    7153     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
    7154     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7155     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7156     * </pre>
    7157     *
    7158     * @param str  the String to parse, may be null
    7159     * @param separatorChars  the characters used as the delimiters,
    7160     *  {@code null} splits on whitespace
    7161     * @param max  the maximum number of elements to include in the
    7162     *  array. A zero or negative value implies no limit
    7163     * @return an array of parsed Strings, {@code null} if null String input
    7164     */
    7165    public static String[] split(final String str, final String separatorChars, final int max) {
    7166        return splitWorker(str, separatorChars, max, false);
    7167    }
    7168
    7169    /**
    7170     * Splits a String by Character type as returned by
    7171     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7172     * characters of the same type are returned as complete tokens.
    7173     * <pre>
    7174     * StringUtils.splitByCharacterType(null)         = null
    7175     * StringUtils.splitByCharacterType("")           = []
    7176     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7177     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7178     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7179     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    7180     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    7181     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    7182     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    7183     * </pre>
    7184     * @param str the String to split, may be {@code null}
    7185     * @return an array of parsed Strings, {@code null} if null String input
    7186     * @since 2.4
    7187     */
    7188    public static String[] splitByCharacterType(final String str) {
    7189        return splitByCharacterType(str, false);
    7190    }
    7191
    7192    /**
    7193     * <p>Splits a String by Character type as returned by
    7194     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7195     * characters of the same type are returned as complete tokens, with the
    7196     * following exception: if {@code camelCase} is {@code true},
    7197     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
    7198     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
    7199     * will belong to the following token rather than to the preceding, if any,
    7200     * {@code Character.UPPERCASE_LETTER} token.
    7201     * @param str the String to split, may be {@code null}
    7202     * @param camelCase whether to use so-called "camel-case" for letter types
    7203     * @return an array of parsed Strings, {@code null} if null String input
    7204     * @since 2.4
    7205     */
    7206    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
    7207        if (str == null) {
    7208            return null;
    7209        }
    7210        if (str.isEmpty()) {
    7211            return ArrayUtils.EMPTY_STRING_ARRAY;
    7212        }
    7213        final char[] c = str.toCharArray();
    7214        final List<String> list = new ArrayList<>();
    7215        int tokenStart = 0;
    7216        int currentType = Character.getType(c[tokenStart]);
    7217        for (int pos = tokenStart + 1; pos < c.length; pos++) {
    7218            final int type = Character.getType(c[pos]);
    7219            if (type == currentType) {
    7220                continue;
    7221            }
    7222            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    7223                final int newTokenStart = pos - 1;
    7224                if (newTokenStart != tokenStart) {
    7225                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    7226                    tokenStart = newTokenStart;
    7227                }
    7228            } else {
    7229                list.add(new String(c, tokenStart, pos - tokenStart));
    7230                tokenStart = pos;
    7231            }
    7232            currentType = type;
    7233        }
    7234        list.add(new String(c, tokenStart, c.length - tokenStart));
    7235        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7236    }
    7237
    7238    /**
    7239     * <p>Splits a String by Character type as returned by
    7240     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7241     * characters of the same type are returned as complete tokens, with the
    7242     * following exception: the character of type
    7243     * {@code Character.UPPERCASE_LETTER}, if any, immediately
    7244     * preceding a token of type {@code Character.LOWERCASE_LETTER}
    7245     * will belong to the following token rather than to the preceding, if any,
    7246     * {@code Character.UPPERCASE_LETTER} token.
    7247     * <pre>
    7248     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    7249     * StringUtils.splitByCharacterTypeCamelCase("")           = []
    7250     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7251     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7252     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7253     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    7254     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    7255     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    7256     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    7257     * </pre>
    7258     * @param str the String to split, may be {@code null}
    7259     * @return an array of parsed Strings, {@code null} if null String input
    7260     * @since 2.4
    7261     */
    7262    public static String[] splitByCharacterTypeCamelCase(final String str) {
    7263        return splitByCharacterType(str, true);
    7264    }
    7265
    7266    /**
    7267     * <p>Splits the provided text into an array, separator string specified.
    7268     *
    7269     * <p>The separator(s) will not be included in the returned String array.
    7270     * Adjacent separators are treated as one separator.</p>
    7271     *
    7272     * <p>A {@code null} input String returns {@code null}.
    7273     * A {@code null} separator splits on whitespace.</p>
    7274     *
    7275     * <pre>
    7276     * StringUtils.splitByWholeSeparator(null, *)               = null
    7277     * StringUtils.splitByWholeSeparator("", *)                 = []
    7278     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    7279     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    7280     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7281     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7282     * </pre>
    7283     *
    7284     * @param str  the String to parse, may be null
    7285     * @param separator  String containing the String to be used as a delimiter,
    7286     *  {@code null} splits on whitespace
    7287     * @return an array of parsed Strings, {@code null} if null String was input
    7288     */
    7289    public static String[] splitByWholeSeparator(final String str, final String separator) {
    7290        return splitByWholeSeparatorWorker(str, separator, -1, false);
    7291    }
    7292
    7293    /**
    7294     * Splits the provided text into an array, separator string specified.
    7295     * Returns a maximum of {@code max} substrings.
    7296     *
    7297     * <p>The separator(s) will not be included in the returned String array.
    7298     * Adjacent separators are treated as one separator.</p>
    7299     *
    7300     * <p>A {@code null} input String returns {@code null}.
    7301     * A {@code null} separator splits on whitespace.</p>
    7302     *
    7303     * <pre>
    7304     * StringUtils.splitByWholeSeparator(null, *, *)               = null
    7305     * StringUtils.splitByWholeSeparator("", *, *)                 = []
    7306     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7307     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    7308     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7309     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7310     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7311     * </pre>
    7312     *
    7313     * @param str  the String to parse, may be null
    7314     * @param separator  String containing the String to be used as a delimiter,
    7315     *  {@code null} splits on whitespace
    7316     * @param max  the maximum number of elements to include in the returned
    7317     *  array. A zero or negative value implies no limit.
    7318     * @return an array of parsed Strings, {@code null} if null String was input
    7319     */
    7320    public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
    7321        return splitByWholeSeparatorWorker(str, separator, max, false);
    7322    }
    7323
    7324    /**
    7325     * Splits the provided text into an array, separator string specified.
    7326     *
    7327     * <p>The separator is not included in the returned String array.
    7328     * Adjacent separators are treated as separators for empty tokens.
    7329     * For more control over the split use the StrTokenizer class.</p>
    7330     *
    7331     * <p>A {@code null} input String returns {@code null}.
    7332     * A {@code null} separator splits on whitespace.</p>
    7333     *
    7334     * <pre>
    7335     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    7336     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    7337     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    7338     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    7339     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7340     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7341     * </pre>
    7342     *
    7343     * @param str  the String to parse, may be null
    7344     * @param separator  String containing the String to be used as a delimiter,
    7345     *  {@code null} splits on whitespace
    7346     * @return an array of parsed Strings, {@code null} if null String was input
    7347     * @since 2.4
    7348     */
    7349    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
    7350        return splitByWholeSeparatorWorker(str, separator, -1, true);
    7351    }
    7352
    7353    /**
    7354     * Splits the provided text into an array, separator string specified.
    7355     * Returns a maximum of {@code max} substrings.
    7356     *
    7357     * <p>The separator is not included in the returned String array.
    7358     * Adjacent separators are treated as separators for empty tokens.
    7359     * For more control over the split use the StrTokenizer class.</p>
    7360     *
    7361     * <p>A {@code null} input String returns {@code null}.
    7362     * A {@code null} separator splits on whitespace.</p>
    7363     *
    7364     * <pre>
    7365     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    7366     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    7367     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7368     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    7369     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7370     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7371     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7372     * </pre>
    7373     *
    7374     * @param str  the String to parse, may be null
    7375     * @param separator  String containing the String to be used as a delimiter,
    7376     *  {@code null} splits on whitespace
    7377     * @param max  the maximum number of elements to include in the returned
    7378     *  array. A zero or negative value implies no limit.
    7379     * @return an array of parsed Strings, {@code null} if null String was input
    7380     * @since 2.4
    7381     */
    7382    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
    7383        return splitByWholeSeparatorWorker(str, separator, max, true);
    7384    }
    7385
    7386    /**
    7387     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
    7388     *
    7389     * @param str  the String to parse, may be {@code null}
    7390     * @param separator  String containing the String to be used as a delimiter,
    7391     *  {@code null} splits on whitespace
    7392     * @param max  the maximum number of elements to include in the returned
    7393     *  array. A zero or negative value implies no limit.
    7394     * @param preserveAllTokens if {@code true}, adjacent separators are
    7395     * treated as empty token separators; if {@code false}, adjacent
    7396     * separators are treated as one separator.
    7397     * @return an array of parsed Strings, {@code null} if null String input
    7398     * @since 2.4
    7399     */
    7400    private static String[] splitByWholeSeparatorWorker(
    7401            final String str, final String separator, final int max, final boolean preserveAllTokens) {
    7402        if (str == null) {
    7403            return null;
    7404        }
    7405
    7406        final int len = str.length();
    7407
    7408        if (len == 0) {
    7409            return ArrayUtils.EMPTY_STRING_ARRAY;
    7410        }
    7411
    7412        if (separator == null || EMPTY.equals(separator)) {
    7413            // Split on whitespace.
    7414            return splitWorker(str, null, max, preserveAllTokens);
    7415        }
    7416
    7417        final int separatorLength = separator.length();
    7418
    7419        final ArrayList<String> substrings = new ArrayList<>();
    7420        int numberOfSubstrings = 0;
    7421        int beg = 0;
    7422        int end = 0;
    7423        while (end < len) {
    7424            end = str.indexOf(separator, beg);
    7425
    7426            if (end > -1) {
    7427                if (end > beg) {
    7428                    numberOfSubstrings += 1;
    7429
    7430                    if (numberOfSubstrings == max) {
    7431                        end = len;
    7432                        substrings.add(str.substring(beg));
    7433                    } else {
    7434                        // The following is OK, because String.substring( beg, end ) excludes
    7435                        // the character at the position 'end'.
    7436                        substrings.add(str.substring(beg, end));
    7437
    7438                        // Set the starting point for the next search.
    7439                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    7440                        // which is the right calculation:
    7441                        beg = end + separatorLength;
    7442                    }
    7443                } else {
    7444                    // We found a consecutive occurrence of the separator, so skip it.
    7445                    if (preserveAllTokens) {
    7446                        numberOfSubstrings += 1;
    7447                        if (numberOfSubstrings == max) {
    7448                            end = len;
    7449                            substrings.add(str.substring(beg));
    7450                        } else {
    7451                            substrings.add(EMPTY);
    7452                        }
    7453                    }
    7454                    beg = end + separatorLength;
    7455                }
    7456            } else {
    7457                // String.substring( beg ) goes from 'beg' to the end of the String.
    7458                substrings.add(str.substring(beg));
    7459                end = len;
    7460            }
    7461        }
    7462
    7463        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7464    }
    7465
    7466    /**
    7467     * Splits the provided text into an array, using whitespace as the
    7468     * separator, preserving all tokens, including empty tokens created by
    7469     * adjacent separators. This is an alternative to using StringTokenizer.
    7470     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7471     *
    7472     * <p>The separator is not included in the returned String array.
    7473     * Adjacent separators are treated as separators for empty tokens.
    7474     * For more control over the split use the StrTokenizer class.</p>
    7475     *
    7476     * <p>A {@code null} input String returns {@code null}.</p>
    7477     *
    7478     * <pre>
    7479     * StringUtils.splitPreserveAllTokens(null)       = null
    7480     * StringUtils.splitPreserveAllTokens("")         = []
    7481     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    7482     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    7483     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    7484     * </pre>
    7485     *
    7486     * @param str  the String to parse, may be {@code null}
    7487     * @return an array of parsed Strings, {@code null} if null String input
    7488     * @since 2.1
    7489     */
    7490    public static String[] splitPreserveAllTokens(final String str) {
    7491        return splitWorker(str, null, -1, true);
    7492    }
    7493
    7494    /**
    7495     * Splits the provided text into an array, separator specified,
    7496     * preserving all tokens, including empty tokens created by adjacent
    7497     * separators. This is an alternative to using StringTokenizer.
    7498     *
    7499     * <p>The separator is not included in the returned String array.
    7500     * Adjacent separators are treated as separators for empty tokens.
    7501     * For more control over the split use the StrTokenizer class.</p>
    7502     *
    7503     * <p>A {@code null} input String returns {@code null}.</p>
    7504     *
    7505     * <pre>
    7506     * StringUtils.splitPreserveAllTokens(null, *)         = null
    7507     * StringUtils.splitPreserveAllTokens("", *)           = []
    7508     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    7509     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    7510     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    7511     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    7512     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    7513     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    7514     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
    7515     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
    7516     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
    7517     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
    7518     * </pre>
    7519     *
    7520     * @param str  the String to parse, may be {@code null}
    7521     * @param separatorChar  the character used as the delimiter,
    7522     *  {@code null} splits on whitespace
    7523     * @return an array of parsed Strings, {@code null} if null String input
    7524     * @since 2.1
    7525     */
    7526    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
    7527        return splitWorker(str, separatorChar, true);
    7528    }
    7529
    7530    /**
    7531     * Splits the provided text into an array, separators specified,
    7532     * preserving all tokens, including empty tokens created by adjacent
    7533     * separators. This is an alternative to using StringTokenizer.
    7534     *
    7535     * <p>The separator is not included in the returned String array.
    7536     * Adjacent separators are treated as separators for empty tokens.
    7537     * For more control over the split use the StrTokenizer class.</p>
    7538     *
    7539     * <p>A {@code null} input String returns {@code null}.
    7540     * A {@code null} separatorChars splits on whitespace.</p>
    7541     *
    7542     * <pre>
    7543     * StringUtils.splitPreserveAllTokens(null, *)           = null
    7544     * StringUtils.splitPreserveAllTokens("", *)             = []
    7545     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    7546     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    7547     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
    7548     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    7549     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    7550     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    7551     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
    7552     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
    7553     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
    7554     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
    7555     * </pre>
    7556     *
    7557     * @param str  the String to parse, may be {@code null}
    7558     * @param separatorChars  the characters used as the delimiters,
    7559     *  {@code null} splits on whitespace
    7560     * @return an array of parsed Strings, {@code null} if null String input
    7561     * @since 2.1
    7562     */
    7563    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
    7564        return splitWorker(str, separatorChars, -1, true);
    7565    }
    7566
    7567    /**
    7568     * Splits the provided text into an array with a maximum length,
    7569     * separators specified, preserving all tokens, including empty tokens
    7570     * created by adjacent separators.
    7571     *
    7572     * <p>The separator is not included in the returned String array.
    7573     * Adjacent separators are treated as separators for empty tokens.
    7574     * Adjacent separators are treated as one separator.</p>
    7575     *
    7576     * <p>A {@code null} input String returns {@code null}.
    7577     * A {@code null} separatorChars splits on whitespace.</p>
    7578     *
    7579     * <p>If more than {@code max} delimited substrings are found, the last
    7580     * returned string includes all characters after the first {@code max - 1}
    7581     * returned strings (including separator characters).</p>
    7582     *
    7583     * <pre>
    7584     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    7585     * StringUtils.splitPreserveAllTokens("", *, *)              = []
    7586     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
    7587     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
    7588     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7589     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7590     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    7591     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    7592     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    7593     * </pre>
    7594     *
    7595     * @param str  the String to parse, may be {@code null}
    7596     * @param separatorChars  the characters used as the delimiters,
    7597     *  {@code null} splits on whitespace
    7598     * @param max  the maximum number of elements to include in the
    7599     *  array. A zero or negative value implies no limit
    7600     * @return an array of parsed Strings, {@code null} if null String input
    7601     * @since 2.1
    7602     */
    7603    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
    7604        return splitWorker(str, separatorChars, max, true);
    7605    }
    7606
    7607    /**
    7608     * Performs the logic for the {@code split} and
    7609     * {@code splitPreserveAllTokens} methods that do not return a
    7610     * maximum array length.
    7611     *
    7612     * @param str  the String to parse, may be {@code null}
    7613     * @param separatorChar the separate character
    7614     * @param preserveAllTokens if {@code true}, adjacent separators are
    7615     * treated as empty token separators; if {@code false}, adjacent
    7616     * separators are treated as one separator.
    7617     * @return an array of parsed Strings, {@code null} if null String input
    7618     */
    7619    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
    7620        // Performance tuned for 2.0 (JDK1.4)
    7621        if (str == null) {
    7622            return null;
    7623        }
    7624        final int len = str.length();
    7625        if (len == 0) {
    7626            return ArrayUtils.EMPTY_STRING_ARRAY;
    7627        }
    7628        final List<String> list = new ArrayList<>();
    7629        int i = 0;
    7630        int start = 0;
    7631        boolean match = false;
    7632        boolean lastMatch = false;
    7633        while (i < len) {
    7634            if (str.charAt(i) == separatorChar) {
    7635                if (match || preserveAllTokens) {
    7636                    list.add(str.substring(start, i));
    7637                    match = false;
    7638                    lastMatch = true;
    7639                }
    7640                start = ++i;
    7641                continue;
    7642            }
    7643            lastMatch = false;
    7644            match = true;
    7645            i++;
    7646        }
    7647        if (match || preserveAllTokens && lastMatch) {
    7648            list.add(str.substring(start, i));
    7649        }
    7650        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7651    }
    7652
    7653    /**
    7654     * Performs the logic for the {@code split} and
    7655     * {@code splitPreserveAllTokens} methods that return a maximum array
    7656     * length.
    7657     *
    7658     * @param str  the String to parse, may be {@code null}
    7659     * @param separatorChars the separate character
    7660     * @param max  the maximum number of elements to include in the
    7661     *  array. A zero or negative value implies no limit.
    7662     * @param preserveAllTokens if {@code true}, adjacent separators are
    7663     * treated as empty token separators; if {@code false}, adjacent
    7664     * separators are treated as one separator.
    7665     * @return an array of parsed Strings, {@code null} if null String input
    7666     */
    7667    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
    7668        // Performance tuned for 2.0 (JDK1.4)
    7669        // Direct code is quicker than StringTokenizer.
    7670        // Also, StringTokenizer uses isSpace() not isWhitespace()
    7671
    7672        if (str == null) {
    7673            return null;
    7674        }
    7675        final int len = str.length();
    7676        if (len == 0) {
    7677            return ArrayUtils.EMPTY_STRING_ARRAY;
    7678        }
    7679        final List<String> list = new ArrayList<>();
    7680        int sizePlus1 = 1;
    7681        int i = 0;
    7682        int start = 0;
    7683        boolean match = false;
    7684        boolean lastMatch = false;
    7685        if (separatorChars == null) {
    7686            // Null separator means use whitespace
    7687            while (i < len) {
    7688                if (Character.isWhitespace(str.charAt(i))) {
    7689                    if (match || preserveAllTokens) {
    7690                        lastMatch = true;
    7691                        if (sizePlus1++ == max) {
    7692                            i = len;
    7693                            lastMatch = false;
    7694                        }
    7695                        list.add(str.substring(start, i));
    7696                        match = false;
    7697                    }
    7698                    start = ++i;
    7699                    continue;
    7700                }
    7701                lastMatch = false;
    7702                match = true;
    7703                i++;
    7704            }
    7705        } else if (separatorChars.length() == 1) {
    7706            // Optimize 1 character case
    7707            final char sep = separatorChars.charAt(0);
    7708            while (i < len) {
    7709                if (str.charAt(i) == sep) {
    7710                    if (match || preserveAllTokens) {
    7711                        lastMatch = true;
    7712                        if (sizePlus1++ == max) {
    7713                            i = len;
    7714                            lastMatch = false;
    7715                        }
    7716                        list.add(str.substring(start, i));
    7717                        match = false;
    7718                    }
    7719                    start = ++i;
    7720                    continue;
    7721                }
    7722                lastMatch = false;
    7723                match = true;
    7724                i++;
    7725            }
    7726        } else {
    7727            // standard case
    7728            while (i < len) {
    7729                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    7730                    if (match || preserveAllTokens) {
    7731                        lastMatch = true;
    7732                        if (sizePlus1++ == max) {
    7733                            i = len;
    7734                            lastMatch = false;
    7735                        }
    7736                        list.add(str.substring(start, i));
    7737                        match = false;
    7738                    }
    7739                    start = ++i;
    7740                    continue;
    7741                }
    7742                lastMatch = false;
    7743                match = true;
    7744                i++;
    7745            }
    7746        }
    7747        if (match || preserveAllTokens && lastMatch) {
    7748            list.add(str.substring(start, i));
    7749        }
    7750        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7751    }
    7752
    7753    /**
    7754     * Tests if a CharSequence starts with a specified prefix.
    7755     *
    7756     * <p>{@code null}s are handled without exceptions. Two {@code null}
    7757     * references are considered to be equal. The comparison is case-sensitive.</p>
    7758     *
    7759     * <pre>
    7760     * StringUtils.startsWith(null, null)      = true
    7761     * StringUtils.startsWith(null, "abc")     = false
    7762     * StringUtils.startsWith("abcdef", null)  = false
    7763     * StringUtils.startsWith("abcdef", "abc") = true
    7764     * StringUtils.startsWith("ABCDEF", "abc") = false
    7765     * </pre>
    7766     *
    7767     * @see String#startsWith(String)
    7768     * @param str  the CharSequence to check, may be null
    7769     * @param prefix the prefix to find, may be null
    7770     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
    7771     *  both {@code null}
    7772     * @since 2.4
    7773     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
    7774     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}
    7775     */
    7776    @Deprecated
    7777    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
    7778        return Strings.CS.startsWith(str, prefix);
    7779    }
    7780
    7781    /**
    7782     * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
    7783     *
    7784     * <pre>
    7785     * StringUtils.startsWithAny(null, null)      = false
    7786     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    7787     * StringUtils.startsWithAny("abcxyz", null)     = false
    7788     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
    7789     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    7790     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    7791     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
    7792     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
    7793     * </pre>
    7794     *
    7795     * @param sequence the CharSequence to check, may be null
    7796     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
    7797     * @see StringUtils#startsWith(CharSequence, CharSequence)
    7798     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    7799     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
    7800     * @since 2.5
    7801     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
    7802     * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CI.startsWithAny(CharSequence, CharSequence...)}
    7803     */
    7804    @Deprecated
    7805    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    7806        return Strings.CS.startsWithAny(sequence, searchStrings);
    7807    }
    7808
    7809    /**
    7810     * Case-insensitive check if a CharSequence starts with a specified prefix.
    7811     *
    7812     * <p>{@code null}s are handled without exceptions. Two {@code null}
    7813     * references are considered to be equal. The comparison is case insensitive.</p>
    7814     *
    7815     * <pre>
    7816     * StringUtils.startsWithIgnoreCase(null, null)      = true
    7817     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    7818     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    7819     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    7820     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    7821     * </pre>
    7822     *
    7823     * @see String#startsWith(String)
    7824     * @param str  the CharSequence to check, may be null
    7825     * @param prefix the prefix to find, may be null
    7826     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
    7827     *  both {@code null}
    7828     * @since 2.4
    7829     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
    7830     * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}
    7831     */
    7832    @Deprecated
    7833    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
    7834        return Strings.CI.startsWith(str, prefix);
    7835    }
    7836
    7837    /**
    7838     * Strips whitespace from the start and end of a String.
    7839     *
    7840     * <p>This is similar to {@link #trim(String)} but removes whitespace.
    7841     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7842     *
    7843     * <p>A {@code null} input String returns {@code null}.</p>
    7844     *
    7845     * <pre>
    7846     * StringUtils.strip(null)     = null
    7847     * StringUtils.strip("")       = ""
    7848     * StringUtils.strip("   ")    = ""
    7849     * StringUtils.strip("abc")    = "abc"
    7850     * StringUtils.strip("  abc")  = "abc"
    7851     * StringUtils.strip("abc  ")  = "abc"
    7852     * StringUtils.strip(" abc ")  = "abc"
    7853     * StringUtils.strip(" ab c ") = "ab c"
    7854     * </pre>
    7855     *
    7856     * @param str  the String to remove whitespace from, may be null
    7857     * @return the stripped String, {@code null} if null String input
    7858     */
    7859    public static String strip(final String str) {
    7860        return strip(str, null);
    7861    }
    7862
    7863    /**
    7864     * Strips any of a set of characters from the start and end of a String.
    7865     * This is similar to {@link String#trim()} but allows the characters
    7866     * to be stripped to be controlled.
    7867     *
    7868     * <p>A {@code null} input String returns {@code null}.
    7869     * An empty string ("") input returns the empty string.</p>
    7870     *
    7871     * <p>If the stripChars String is {@code null}, whitespace is
    7872     * stripped as defined by {@link Character#isWhitespace(char)}.
    7873     * Alternatively use {@link #strip(String)}.</p>
    7874     *
    7875     * <pre>
    7876     * StringUtils.strip(null, *)          = null
    7877     * StringUtils.strip("", *)            = ""
    7878     * StringUtils.strip("abc", null)      = "abc"
    7879     * StringUtils.strip("  abc", null)    = "abc"
    7880     * StringUtils.strip("abc  ", null)    = "abc"
    7881     * StringUtils.strip(" abc ", null)    = "abc"
    7882     * StringUtils.strip("  abcyx", "xyz") = "  abc"
    7883     * </pre>
    7884     *
    7885     * @param str  the String to remove characters from, may be null
    7886     * @param stripChars  the characters to remove, null treated as whitespace
    7887     * @return the stripped String, {@code null} if null String input
    7888     */
    7889    public static String strip(String str, final String stripChars) {
    7890        str = stripStart(str, stripChars);
    7891        return stripEnd(str, stripChars);
    7892    }
    7893
    7894    /**
    7895     * Removes diacritics (~= accents) from a string. The case will not be altered.
    7896     * <p>
    7897     * For instance, '&agrave;' will be replaced by 'a'.
    7898     * </p>
    7899     * <p>
    7900     * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
    7901     * </p>
    7902     * <pre>
    7903     * StringUtils.stripAccents(null)         = null
    7904     * StringUtils.stripAccents("")           = ""
    7905     * StringUtils.stripAccents("control")    = "control"
    7906     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
    7907     * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
    7908     * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
    7909     * </pre>
    7910     * <p>
    7911     * See also <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
    7912     * </p>
    7913     *
    7914     * @param input String to be stripped
    7915     * @return input text with diacritics removed
    7916     * @since 3.0
    7917     */
    7918    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
    7919    public static String stripAccents(final String input) {
    7920        if (isEmpty(input)) {
    7921            return input;
    7922        }
    7923        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
    7924        convertRemainingAccentCharacters(decomposed);
    7925        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
    7926    }
    7927
    7928    /**
    7929     * Strips whitespace from the start and end of every String in an array.
    7930     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7931     *
    7932     * <p>A new array is returned each time, except for length zero.
    7933     * A {@code null} array will return {@code null}.
    7934     * An empty array will return itself.
    7935     * A {@code null} array entry will be ignored.</p>
    7936     *
    7937     * <pre>
    7938     * StringUtils.stripAll(null)             = null
    7939     * StringUtils.stripAll([])               = []
    7940     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    7941     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    7942     * </pre>
    7943     *
    7944     * @param strs  the array to remove whitespace from, may be null
    7945     * @return the stripped Strings, {@code null} if null array input
    7946     */
    7947    public static String[] stripAll(final String... strs) {
    7948        return stripAll(strs, null);
    7949    }
    7950
    7951    /**
    7952     * Strips any of a set of characters from the start and end of every
    7953     * String in an array.
    7954     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7955     *
    7956     * <p>A new array is returned each time, except for length zero.
    7957     * A {@code null} array will return {@code null}.
    7958     * An empty array will return itself.
    7959     * A {@code null} array entry will be ignored.
    7960     * A {@code null} stripChars will strip whitespace as defined by
    7961     * {@link Character#isWhitespace(char)}.</p>
    7962     *
    7963     * <pre>
    7964     * StringUtils.stripAll(null, *)                = null
    7965     * StringUtils.stripAll([], *)                  = []
    7966     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    7967     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    7968     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    7969     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    7970     * </pre>
    7971     *
    7972     * @param strs  the array to remove characters from, may be null
    7973     * @param stripChars  the characters to remove, null treated as whitespace
    7974     * @return the stripped Strings, {@code null} if null array input
    7975     */
    7976    public static String[] stripAll(final String[] strs, final String stripChars) {
    7977        final int strsLen = ArrayUtils.getLength(strs);
    7978        if (strsLen == 0) {
    7979            return strs;
    7980        }
    7981        final String[] newArr = new String[strsLen];
    7982        Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
    7983        return newArr;
    7984    }
    7985
    7986    /**
    7987     * Strips any of a set of characters from the end of a String.
    7988     *
    7989     * <p>A {@code null} input String returns {@code null}.
    7990     * An empty string ("") input returns the empty string.</p>
    7991     *
    7992     * <p>If the stripChars String is {@code null}, whitespace is
    7993     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    7994     *
    7995     * <pre>
    7996     * StringUtils.stripEnd(null, *)          = null
    7997     * StringUtils.stripEnd("", *)            = ""
    7998     * StringUtils.stripEnd("abc", "")        = "abc"
    7999     * StringUtils.stripEnd("abc", null)      = "abc"
    8000     * StringUtils.stripEnd("  abc", null)    = "  abc"
    8001     * StringUtils.stripEnd("abc  ", null)    = "abc"
    8002     * StringUtils.stripEnd(" abc ", null)    = " abc"
    8003     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    8004     * StringUtils.stripEnd("120.00", ".0")   = "12"
    8005     * </pre>
    8006     *
    8007     * @param str  the String to remove characters from, may be null
    8008     * @param stripChars  the set of characters to remove, null treated as whitespace
    8009     * @return the stripped String, {@code null} if null String input
    8010     */
    8011    public static String stripEnd(final String str, final String stripChars) {
    8012        int end = length(str);
    8013        if (end == 0) {
    8014            return str;
    8015        }
    8016
    8017        if (stripChars == null) {
    8018            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
    8019                end--;
    8020            }
    8021        } else if (stripChars.isEmpty()) {
    8022            return str;
    8023        } else {
    8024            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
    8025                end--;
    8026            }
    8027        }
    8028        return str.substring(0, end);
    8029    }
    8030
    8031    /**
    8032     * Strips any of a set of characters from the start of a String.
    8033     *
    8034     * <p>A {@code null} input String returns {@code null}.
    8035     * An empty string ("") input returns the empty string.</p>
    8036     *
    8037     * <p>If the stripChars String is {@code null}, whitespace is
    8038     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8039     *
    8040     * <pre>
    8041     * StringUtils.stripStart(null, *)          = null
    8042     * StringUtils.stripStart("", *)            = ""
    8043     * StringUtils.stripStart("abc", "")        = "abc"
    8044     * StringUtils.stripStart("abc", null)      = "abc"
    8045     * StringUtils.stripStart("  abc", null)    = "abc"
    8046     * StringUtils.stripStart("abc  ", null)    = "abc  "
    8047     * StringUtils.stripStart(" abc ", null)    = "abc "
    8048     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    8049     * </pre>
    8050     *
    8051     * @param str  the String to remove characters from, may be null
    8052     * @param stripChars  the characters to remove, null treated as whitespace
    8053     * @return the stripped String, {@code null} if null String input
    8054     */
    8055    public static String stripStart(final String str, final String stripChars) {
    8056        final int strLen = length(str);
    8057        if (strLen == 0) {
    8058            return str;
    8059        }
    8060        int start = 0;
    8061        if (stripChars == null) {
    8062            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
    8063                start++;
    8064            }
    8065        } else if (stripChars.isEmpty()) {
    8066            return str;
    8067        } else {
    8068            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
    8069                start++;
    8070            }
    8071        }
    8072        return str.substring(start);
    8073    }
    8074
    8075    /**
    8076     * Strips whitespace from the start and end of a String  returning
    8077     * an empty String if {@code null} input.
    8078     *
    8079     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
    8080     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8081     *
    8082     * <pre>
    8083     * StringUtils.stripToEmpty(null)     = ""
    8084     * StringUtils.stripToEmpty("")       = ""
    8085     * StringUtils.stripToEmpty("   ")    = ""
    8086     * StringUtils.stripToEmpty("abc")    = "abc"
    8087     * StringUtils.stripToEmpty("  abc")  = "abc"
    8088     * StringUtils.stripToEmpty("abc  ")  = "abc"
    8089     * StringUtils.stripToEmpty(" abc ")  = "abc"
    8090     * StringUtils.stripToEmpty(" ab c ") = "ab c"
    8091     * </pre>
    8092     *
    8093     * @param str  the String to be stripped, may be null
    8094     * @return the trimmed String, or an empty String if {@code null} input
    8095     * @since 2.0
    8096     */
    8097    public static String stripToEmpty(final String str) {
    8098        return str == null ? EMPTY : strip(str, null);
    8099    }
    8100
    8101    /**
    8102     * Strips whitespace from the start and end of a String  returning
    8103     * {@code null} if the String is empty ("") after the strip.
    8104     *
    8105     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
    8106     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8107     *
    8108     * <pre>
    8109     * StringUtils.stripToNull(null)     = null
    8110     * StringUtils.stripToNull("")       = null
    8111     * StringUtils.stripToNull("   ")    = null
    8112     * StringUtils.stripToNull("abc")    = "abc"
    8113     * StringUtils.stripToNull("  abc")  = "abc"
    8114     * StringUtils.stripToNull("abc  ")  = "abc"
    8115     * StringUtils.stripToNull(" abc ")  = "abc"
    8116     * StringUtils.stripToNull(" ab c ") = "ab c"
    8117     * </pre>
    8118     *
    8119     * @param str  the String to be stripped, may be null
    8120     * @return the stripped String,
    8121     *  {@code null} if whitespace, empty or null String input
    8122     * @since 2.0
    8123     */
    8124    public static String stripToNull(String str) {
    8125        if (str == null) {
    8126            return null;
    8127        }
    8128        str = strip(str, null);
    8129        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
    8130    }
    8131
    8132    /**
    8133     * Gets a substring from the specified String avoiding exceptions.
    8134     *
    8135     * <p>A negative start position can be used to start {@code n}
    8136     * characters from the end of the String.</p>
    8137     *
    8138     * <p>A {@code null} String will return {@code null}.
    8139     * An empty ("") String will return "".</p>
    8140     *
    8141     * <pre>
    8142     * StringUtils.substring(null, *)   = null
    8143     * StringUtils.substring("", *)     = ""
    8144     * StringUtils.substring("abc", 0)  = "abc"
    8145     * StringUtils.substring("abc", 2)  = "c"
    8146     * StringUtils.substring("abc", 4)  = ""
    8147     * StringUtils.substring("abc", -2) = "bc"
    8148     * StringUtils.substring("abc", -4) = "abc"
    8149     * </pre>
    8150     *
    8151     * @param str  the String to get the substring from, may be null
    8152     * @param start  the position to start from, negative means
    8153     *  count back from the end of the String by this many characters
    8154     * @return substring from start position, {@code null} if null String input
    8155     */
    8156    public static String substring(final String str, int start) {
    8157        if (str == null) {
    8158            return null;
    8159        }
    8160
    8161        // handle negatives, which means last n characters
    8162        if (start < 0) {
    8163            start = str.length() + start; // remember start is negative
    8164        }
    8165
    8166        if (start < 0) {
    8167            start = 0;
    8168        }
    8169        if (start > str.length()) {
    8170            return EMPTY;
    8171        }
    8172
    8173        return str.substring(start);
    8174    }
    8175
    8176    /**
    8177     * Gets a substring from the specified String avoiding exceptions.
    8178     *
    8179     * <p>A negative start position can be used to start/end {@code n}
    8180     * characters from the end of the String.</p>
    8181     *
    8182     * <p>The returned substring starts with the character in the {@code start}
    8183     * position and ends before the {@code end} position. All position counting is
    8184     * zero-based -- i.e., to start at the beginning of the string use
    8185     * {@code start = 0}. Negative start and end positions can be used to
    8186     * specify offsets relative to the end of the String.</p>
    8187     *
    8188     * <p>If {@code start} is not strictly to the left of {@code end}, ""
    8189     * is returned.</p>
    8190     *
    8191     * <pre>
    8192     * StringUtils.substring(null, *, *)    = null
    8193     * StringUtils.substring("", * ,  *)    = "";
    8194     * StringUtils.substring("abc", 0, 2)   = "ab"
    8195     * StringUtils.substring("abc", 2, 0)   = ""
    8196     * StringUtils.substring("abc", 2, 4)   = "c"
    8197     * StringUtils.substring("abc", 4, 6)   = ""
    8198     * StringUtils.substring("abc", 2, 2)   = ""
    8199     * StringUtils.substring("abc", -2, -1) = "b"
    8200     * StringUtils.substring("abc", -4, 2)  = "ab"
    8201     * </pre>
    8202     *
    8203     * @param str  the String to get the substring from, may be null
    8204     * @param start  the position to start from, negative means
    8205     *  count back from the end of the String by this many characters
    8206     * @param end  the position to end at (exclusive), negative means
    8207     *  count back from the end of the String by this many characters
    8208     * @return substring from start position to end position,
    8209     *  {@code null} if null String input
    8210     */
    8211    public static String substring(final String str, int start, int end) {
    8212        if (str == null) {
    8213            return null;
    8214        }
    8215
    8216        // handle negatives
    8217        if (end < 0) {
    8218            end = str.length() + end; // remember end is negative
    8219        }
    8220        if (start < 0) {
    8221            start = str.length() + start; // remember start is negative
    8222        }
    8223
    8224        // check length next
    8225        if (end > str.length()) {
    8226            end = str.length();
    8227        }
    8228
    8229        // if start is greater than end, return ""
    8230        if (start > end) {
    8231            return EMPTY;
    8232        }
    8233
    8234        if (start < 0) {
    8235            start = 0;
    8236        }
    8237        if (end < 0) {
    8238            end = 0;
    8239        }
    8240
    8241        return str.substring(start, end);
    8242    }
    8243
    8244    /**
    8245     * Gets the substring after the first occurrence of a separator.
    8246     * The separator is not returned.
    8247     *
    8248     * <p>A {@code null} string input will return {@code null}.
    8249     * An empty ("") string input will return the empty string.
    8250     *
    8251     * <p>If nothing is found, the empty string is returned.</p>
    8252     *
    8253     * <pre>
    8254     * StringUtils.substringAfter(null, *)      = null
    8255     * StringUtils.substringAfter("", *)        = ""
    8256     * StringUtils.substringAfter("abc", 'a')   = "bc"
    8257     * StringUtils.substringAfter("abcba", 'b') = "cba"
    8258     * StringUtils.substringAfter("abc", 'c')   = ""
    8259     * StringUtils.substringAfter("abc", 'd')   = ""
    8260     * StringUtils.substringAfter(" abc", 32)   = "abc"
    8261     * </pre>
    8262     *
    8263     * @param str  the String to get a substring from, may be null
    8264     * @param separator  the character (Unicode code point) to search.
    8265     * @return the substring after the first occurrence of the separator,
    8266     *  {@code null} if null String input
    8267     * @since 3.11
    8268     */
    8269    public static String substringAfter(final String str, final int separator) {
    8270        if (isEmpty(str)) {
    8271            return str;
    8272        }
    8273        final int pos = str.indexOf(separator);
    8274        if (pos == INDEX_NOT_FOUND) {
    8275            return EMPTY;
    8276        }
    8277        return str.substring(pos + 1);
    8278    }
    8279
    8280    /**
    8281     * Gets the substring after the first occurrence of a separator.
    8282     * The separator is not returned.
    8283     *
    8284     * <p>A {@code null} string input will return {@code null}.
    8285     * An empty ("") string input will return the empty string.
    8286     * A {@code null} separator will return the empty string if the
    8287     * input string is not {@code null}.</p>
    8288     *
    8289     * <p>If nothing is found, the empty string is returned.</p>
    8290     *
    8291     * <pre>
    8292     * StringUtils.substringAfter(null, *)      = null
    8293     * StringUtils.substringAfter("", *)        = ""
    8294     * StringUtils.substringAfter(*, null)      = ""
    8295     * StringUtils.substringAfter("abc", "a")   = "bc"
    8296     * StringUtils.substringAfter("abcba", "b") = "cba"
    8297     * StringUtils.substringAfter("abc", "c")   = ""
    8298     * StringUtils.substringAfter("abc", "d")   = ""
    8299     * StringUtils.substringAfter("abc", "")    = "abc"
    8300     * </pre>
    8301     *
    8302     * @param str  the String to get a substring from, may be null
    8303     * @param separator  the String to search for, may be null
    8304     * @return the substring after the first occurrence of the separator,
    8305     *  {@code null} if null String input
    8306     * @since 2.0
    8307     */
    8308    public static String substringAfter(final String str, final String separator) {
    8309        if (isEmpty(str)) {
    8310            return str;
    8311        }
    8312        if (separator == null) {
    8313            return EMPTY;
    8314        }
    8315        final int pos = str.indexOf(separator);
    8316        if (pos == INDEX_NOT_FOUND) {
    8317            return EMPTY;
    8318        }
    8319        return str.substring(pos + separator.length());
    8320    }
    8321
    8322    /**
    8323     * Gets the substring after the last occurrence of a separator.
    8324     * The separator is not returned.
    8325     *
    8326     * <p>A {@code null} string input will return {@code null}.
    8327     * An empty ("") string input will return the empty string.
    8328     *
    8329     * <p>If nothing is found, the empty string is returned.</p>
    8330     *
    8331     * <pre>
    8332     * StringUtils.substringAfterLast(null, *)      = null
    8333     * StringUtils.substringAfterLast("", *)        = ""
    8334     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
    8335     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
    8336     * StringUtils.substringAfterLast("abcba", 'b') = "a"
    8337     * StringUtils.substringAfterLast("abc", 'c')   = ""
    8338     * StringUtils.substringAfterLast("a", 'a')     = ""
    8339     * StringUtils.substringAfterLast("a", 'z')     = ""
    8340     * </pre>
    8341     *
    8342     * @param str  the String to get a substring from, may be null
    8343     * @param separator  the character (Unicode code point) to search.
    8344     * @return the substring after the last occurrence of the separator,
    8345     *  {@code null} if null String input
    8346     * @since 3.11
    8347     */
    8348    public static String substringAfterLast(final String str, final int separator) {
    8349        if (isEmpty(str)) {
    8350            return str;
    8351        }
    8352        final int pos = str.lastIndexOf(separator);
    8353        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
    8354            return EMPTY;
    8355        }
    8356        return str.substring(pos + 1);
    8357    }
    8358
    8359    /**
    8360     * Gets the substring after the last occurrence of a separator.
    8361     * The separator is not returned.
    8362     *
    8363     * <p>A {@code null} string input will return {@code null}.
    8364     * An empty ("") string input will return the empty string.
    8365     * An empty or {@code null} separator will return the empty string if
    8366     * the input string is not {@code null}.</p>
    8367     *
    8368     * <p>If nothing is found, the empty string is returned.</p>
    8369     *
    8370     * <pre>
    8371     * StringUtils.substringAfterLast(null, *)      = null
    8372     * StringUtils.substringAfterLast("", *)        = ""
    8373     * StringUtils.substringAfterLast(*, "")        = ""
    8374     * StringUtils.substringAfterLast(*, null)      = ""
    8375     * StringUtils.substringAfterLast("abc", "a")   = "bc"
    8376     * StringUtils.substringAfterLast("abcba", "b") = "a"
    8377     * StringUtils.substringAfterLast("abc", "c")   = ""
    8378     * StringUtils.substringAfterLast("a", "a")     = ""
    8379     * StringUtils.substringAfterLast("a", "z")     = ""
    8380     * </pre>
    8381     *
    8382     * @param str  the String to get a substring from, may be null
    8383     * @param separator  the String to search for, may be null
    8384     * @return the substring after the last occurrence of the separator,
    8385     *  {@code null} if null String input
    8386     * @since 2.0
    8387     */
    8388    public static String substringAfterLast(final String str, final String separator) {
    8389        if (isEmpty(str)) {
    8390            return str;
    8391        }
    8392        if (isEmpty(separator)) {
    8393            return EMPTY;
    8394        }
    8395        final int pos = str.lastIndexOf(separator);
    8396        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
    8397            return EMPTY;
    8398        }
    8399        return str.substring(pos + separator.length());
    8400    }
    8401
    8402    /**
    8403     * Gets the substring before the first occurrence of a separator. The separator is not returned.
    8404     *
    8405     * <p>
    8406     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8407     * </p>
    8408     *
    8409     * <p>
    8410     * If nothing is found, the string input is returned.
    8411     * </p>
    8412     *
    8413     * <pre>
    8414     * StringUtils.substringBefore(null, *)      = null
    8415     * StringUtils.substringBefore("", *)        = ""
    8416     * StringUtils.substringBefore("abc", 'a')   = ""
    8417     * StringUtils.substringBefore("abcba", 'b') = "a"
    8418     * StringUtils.substringBefore("abc", 'c')   = "ab"
    8419     * StringUtils.substringBefore("abc", 'd')   = "abc"
    8420     * </pre>
    8421     *
    8422     * @param str the String to get a substring from, may be null
    8423     * @param separator the character (Unicode code point) to search.
    8424     * @return the substring before the first occurrence of the separator, {@code null} if null String input
    8425     * @since 3.12.0
    8426     */
    8427    public static String substringBefore(final String str, final int separator) {
    8428        if (isEmpty(str)) {
    8429            return str;
    8430        }
    8431        final int pos = str.indexOf(separator);
    8432        if (pos == INDEX_NOT_FOUND) {
    8433            return str;
    8434        }
    8435        return str.substring(0, pos);
    8436    }
    8437
    8438    /**
    8439     * Gets the substring before the first occurrence of a separator.
    8440     * The separator is not returned.
    8441     *
    8442     * <p>A {@code null} string input will return {@code null}.
    8443     * An empty ("") string input will return the empty string.
    8444     * A {@code null} separator will return the input string.</p>
    8445     *
    8446     * <p>If nothing is found, the string input is returned.</p>
    8447     *
    8448     * <pre>
    8449     * StringUtils.substringBefore(null, *)      = null
    8450     * StringUtils.substringBefore("", *)        = ""
    8451     * StringUtils.substringBefore("abc", "a")   = ""
    8452     * StringUtils.substringBefore("abcba", "b") = "a"
    8453     * StringUtils.substringBefore("abc", "c")   = "ab"
    8454     * StringUtils.substringBefore("abc", "d")   = "abc"
    8455     * StringUtils.substringBefore("abc", "")    = ""
    8456     * StringUtils.substringBefore("abc", null)  = "abc"
    8457     * </pre>
    8458     *
    8459     * @param str  the String to get a substring from, may be null
    8460     * @param separator  the String to search for, may be null
    8461     * @return the substring before the first occurrence of the separator,
    8462     *  {@code null} if null String input
    8463     * @since 2.0
    8464     */
    8465    public static String substringBefore(final String str, final String separator) {
    8466        if (isEmpty(str) || separator == null) {
    8467            return str;
    8468        }
    8469        if (separator.isEmpty()) {
    8470            return EMPTY;
    8471        }
    8472        final int pos = str.indexOf(separator);
    8473        if (pos == INDEX_NOT_FOUND) {
    8474            return str;
    8475        }
    8476        return str.substring(0, pos);
    8477    }
    8478
    8479    /**
    8480     * Gets the substring before the last occurrence of a separator.
    8481     * The separator is not returned.
    8482     *
    8483     * <p>A {@code null} string input will return {@code null}.
    8484     * An empty ("") string input will return the empty string.
    8485     * An empty or {@code null} separator will return the input string.</p>
    8486     *
    8487     * <p>If nothing is found, the string input is returned.</p>
    8488     *
    8489     * <pre>
    8490     * StringUtils.substringBeforeLast(null, *)      = null
    8491     * StringUtils.substringBeforeLast("", *)        = ""
    8492     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    8493     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    8494     * StringUtils.substringBeforeLast("a", "a")     = ""
    8495     * StringUtils.substringBeforeLast("a", "z")     = "a"
    8496     * StringUtils.substringBeforeLast("a", null)    = "a"
    8497     * StringUtils.substringBeforeLast("a", "")      = "a"
    8498     * </pre>
    8499     *
    8500     * @param str  the String to get a substring from, may be null
    8501     * @param separator  the String to search for, may be null
    8502     * @return the substring before the last occurrence of the separator,
    8503     *  {@code null} if null String input
    8504     * @since 2.0
    8505     */
    8506    public static String substringBeforeLast(final String str, final String separator) {
    8507        if (isEmpty(str) || isEmpty(separator)) {
    8508            return str;
    8509        }
    8510        final int pos = str.lastIndexOf(separator);
    8511        if (pos == INDEX_NOT_FOUND) {
    8512            return str;
    8513        }
    8514        return str.substring(0, pos);
    8515    }
    8516
    8517    /**
    8518     * Gets the String that is nested in between two instances of the
    8519     * same String.
    8520     *
    8521     * <p>A {@code null} input String returns {@code null}.
    8522     * A {@code null} tag returns {@code null}.</p>
    8523     *
    8524     * <pre>
    8525     * StringUtils.substringBetween(null, *)            = null
    8526     * StringUtils.substringBetween("", "")             = ""
    8527     * StringUtils.substringBetween("", "tag")          = null
    8528     * StringUtils.substringBetween("tagabctag", null)  = null
    8529     * StringUtils.substringBetween("tagabctag", "")    = ""
    8530     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    8531     * </pre>
    8532     *
    8533     * @param str  the String containing the substring, may be null
    8534     * @param tag  the String before and after the substring, may be null
    8535     * @return the substring, {@code null} if no match
    8536     * @since 2.0
    8537     */
    8538    public static String substringBetween(final String str, final String tag) {
    8539        return substringBetween(str, tag, tag);
    8540    }
    8541
    8542    /**
    8543     * Gets the String that is nested in between two Strings.
    8544     * Only the first match is returned.
    8545     *
    8546     * <p>A {@code null} input String returns {@code null}.
    8547     * A {@code null} open/close returns {@code null} (no match).
    8548     * An empty ("") open and close returns an empty string.</p>
    8549     *
    8550     * <pre>
    8551     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    8552     * StringUtils.substringBetween(null, *, *)          = null
    8553     * StringUtils.substringBetween(*, null, *)          = null
    8554     * StringUtils.substringBetween(*, *, null)          = null
    8555     * StringUtils.substringBetween("", "", "")          = ""
    8556     * StringUtils.substringBetween("", "", "]")         = null
    8557     * StringUtils.substringBetween("", "[", "]")        = null
    8558     * StringUtils.substringBetween("yabcz", "", "")     = ""
    8559     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    8560     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    8561     * </pre>
    8562     *
    8563     * @param str  the String containing the substring, may be null
    8564     * @param open  the String before the substring, may be null
    8565     * @param close  the String after the substring, may be null
    8566     * @return the substring, {@code null} if no match
    8567     * @since 2.0
    8568     */
    8569    public static String substringBetween(final String str, final String open, final String close) {
    8570        if (!ObjectUtils.allNotNull(str, open, close)) {
    8571            return null;
    8572        }
    8573        final int start = str.indexOf(open);
    8574        if (start != INDEX_NOT_FOUND) {
    8575            final int end = str.indexOf(close, start + open.length());
    8576            if (end != INDEX_NOT_FOUND) {
    8577                return str.substring(start + open.length(), end);
    8578            }
    8579        }
    8580        return null;
    8581    }
    8582
    8583    /**
    8584     * Searches a String for substrings delimited by a start and end tag,
    8585     * returning all matching substrings in an array.
    8586     *
    8587     * <p>A {@code null} input String returns {@code null}.
    8588     * A {@code null} open/close returns {@code null} (no match).
    8589     * An empty ("") open/close returns {@code null} (no match).</p>
    8590     *
    8591     * <pre>
    8592     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    8593     * StringUtils.substringsBetween(null, *, *)            = null
    8594     * StringUtils.substringsBetween(*, null, *)            = null
    8595     * StringUtils.substringsBetween(*, *, null)            = null
    8596     * StringUtils.substringsBetween("", "[", "]")          = []
    8597     * </pre>
    8598     *
    8599     * @param str  the String containing the substrings, null returns null, empty returns empty
    8600     * @param open  the String identifying the start of the substring, empty returns null
    8601     * @param close  the String identifying the end of the substring, empty returns null
    8602     * @return a String Array of substrings, or {@code null} if no match
    8603     * @since 2.3
    8604     */
    8605    public static String[] substringsBetween(final String str, final String open, final String close) {
    8606        if (str == null || isEmpty(open) || isEmpty(close)) {
    8607            return null;
    8608        }
    8609        final int strLen = str.length();
    8610        if (strLen == 0) {
    8611            return ArrayUtils.EMPTY_STRING_ARRAY;
    8612        }
    8613        final int closeLen = close.length();
    8614        final int openLen = open.length();
    8615        final List<String> list = new ArrayList<>();
    8616        int pos = 0;
    8617        while (pos < strLen - closeLen) {
    8618            int start = str.indexOf(open, pos);
    8619            if (start < 0) {
    8620                break;
    8621            }
    8622            start += openLen;
    8623            final int end = str.indexOf(close, start);
    8624            if (end < 0) {
    8625                break;
    8626            }
    8627            list.add(str.substring(start, end));
    8628            pos = end + closeLen;
    8629        }
    8630        if (list.isEmpty()) {
    8631            return null;
    8632        }
    8633        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    8634    }
    8635
    8636    /**
    8637     * Swaps the case of a String changing upper and title case to
    8638     * lower case, and lower case to upper case.
    8639     *
    8640     * <ul>
    8641     *  <li>Upper case character converts to Lower case</li>
    8642     *  <li>Title case character converts to Lower case</li>
    8643     *  <li>Lower case character converts to Upper case</li>
    8644     * </ul>
    8645     *
    8646     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
    8647     * A {@code null} input String returns {@code null}.</p>
    8648     *
    8649     * <pre>
    8650     * StringUtils.swapCase(null)                 = null
    8651     * StringUtils.swapCase("")                   = ""
    8652     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    8653     * </pre>
    8654     *
    8655     * <p>NOTE: This method changed in Lang version 2.0.
    8656     * It no longer performs a word based algorithm.
    8657     * If you only use ASCII, you will notice no change.
    8658     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
    8659     *
    8660     * @param str  the String to swap case, may be null
    8661     * @return the changed String, {@code null} if null String input
    8662     */
    8663    public static String swapCase(final String str) {
    8664        if (isEmpty(str)) {
    8665            return str;
    8666        }
    8667
    8668        final int strLen = str.length();
    8669        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    8670        int outOffset = 0;
    8671        for (int i = 0; i < strLen; ) {
    8672            final int oldCodepoint = str.codePointAt(i);
    8673            final int newCodePoint;
    8674            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
    8675                newCodePoint = Character.toLowerCase(oldCodepoint);
    8676            } else if (Character.isLowerCase(oldCodepoint)) {
    8677                newCodePoint = Character.toUpperCase(oldCodepoint);
    8678            } else {
    8679                newCodePoint = oldCodepoint;
    8680            }
    8681            newCodePoints[outOffset++] = newCodePoint;
    8682            i += Character.charCount(newCodePoint);
    8683         }
    8684        return new String(newCodePoints, 0, outOffset);
    8685    }
    8686
    8687    /**
    8688     * Converts a {@link CharSequence} into an array of code points.
    8689     *
    8690     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
    8691     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
    8692     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
    8693     *
    8694     * <pre>
    8695     * StringUtils.toCodePoints(null)   =  null
    8696     * StringUtils.toCodePoints("")     =  []  // empty array
    8697     * </pre>
    8698     *
    8699     * @param cs the character sequence to convert
    8700     * @return an array of code points
    8701     * @since 3.6
    8702     */
    8703    public static int[] toCodePoints(final CharSequence cs) {
    8704        if (cs == null) {
    8705            return null;
    8706        }
    8707        if (cs.length() == 0) {
    8708            return ArrayUtils.EMPTY_INT_ARRAY;
    8709        }
    8710        return cs.toString().codePoints().toArray();
    8711    }
    8712
    8713    /**
    8714     * Converts a {@code byte[]} to a String using the specified character encoding.
    8715     *
    8716     * @param bytes
    8717     *            the byte array to read from
    8718     * @param charset
    8719     *            the encoding to use, if null then use the platform default
    8720     * @return a new String
    8721     * @throws NullPointerException
    8722     *             if {@code bytes} is null
    8723     * @since 3.2
    8724     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
    8725     */
    8726    public static String toEncodedString(final byte[] bytes, final Charset charset) {
    8727        return new String(bytes, Charsets.toCharset(charset));
    8728    }
    8729
    8730    /**
    8731     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
    8732     *
    8733     * @param source A source String or null.
    8734     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
    8735     * @since 3.10
    8736     */
    8737    public static String toRootLowerCase(final String source) {
    8738        return source == null ? null : source.toLowerCase(Locale.ROOT);
    8739    }
    8740
    8741    /**
    8742     * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
    8743     *
    8744     * @param source A source String or null.
    8745     * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
    8746     * @since 3.10
    8747     */
    8748    public static String toRootUpperCase(final String source) {
    8749        return source == null ? null : source.toUpperCase(Locale.ROOT);
    8750    }
    8751
    8752    /**
    8753     * Converts a {@code byte[]} to a String using the specified character encoding.
    8754     *
    8755     * @param bytes
    8756     *            the byte array to read from
    8757     * @param charsetName
    8758     *            the encoding to use, if null then use the platform default
    8759     * @return a new String
    8760     * @throws NullPointerException
    8761     *             if the input is null
    8762     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
    8763     * @since 3.1
    8764     */
    8765    @Deprecated
    8766    public static String toString(final byte[] bytes, final String charsetName) {
    8767        return new String(bytes, Charsets.toCharset(charsetName));
    8768    }
    8769
    8770    /**
    8771     * Removes control characters (char &lt;= 32) from both
    8772     * ends of this String, handling {@code null} by returning
    8773     * {@code null}.
    8774     *
    8775     * <p>The String is trimmed using {@link String#trim()}.
    8776     * Trim removes start and end characters &lt;= 32.
    8777     * To strip whitespace use {@link #strip(String)}.</p>
    8778     *
    8779     * <p>To trim your choice of characters, use the
    8780     * {@link #strip(String, String)} methods.</p>
    8781     *
    8782     * <pre>
    8783     * StringUtils.trim(null)          = null
    8784     * StringUtils.trim("")            = ""
    8785     * StringUtils.trim("     ")       = ""
    8786     * StringUtils.trim("abc")         = "abc"
    8787     * StringUtils.trim("    abc    ") = "abc"
    8788     * </pre>
    8789     *
    8790     * @param str  the String to be trimmed, may be null
    8791     * @return the trimmed string, {@code null} if null String input
    8792     */
    8793    public static String trim(final String str) {
    8794        return str == null ? null : str.trim();
    8795    }
    8796
    8797    /**
    8798     * Removes control characters (char &lt;= 32) from both
    8799     * ends of this String returning an empty String ("") if the String
    8800     * is empty ("") after the trim or if it is {@code null}.
    8801     *
    8802     * <p>The String is trimmed using {@link String#trim()}.
    8803     * Trim removes start and end characters &lt;= 32.
    8804     * To strip whitespace use {@link #stripToEmpty(String)}.
    8805     *
    8806     * <pre>
    8807     * StringUtils.trimToEmpty(null)          = ""
    8808     * StringUtils.trimToEmpty("")            = ""
    8809     * StringUtils.trimToEmpty("     ")       = ""
    8810     * StringUtils.trimToEmpty("abc")         = "abc"
    8811     * StringUtils.trimToEmpty("    abc    ") = "abc"
    8812     * </pre>
    8813     *
    8814     * @param str  the String to be trimmed, may be null
    8815     * @return the trimmed String, or an empty String if {@code null} input
    8816     * @since 2.0
    8817     */
    8818    public static String trimToEmpty(final String str) {
    8819        return str == null ? EMPTY : str.trim();
    8820    }
    8821
    8822    /**
    8823     * Removes control characters (char &lt;= 32) from both
    8824     * ends of this String returning {@code null} if the String is
    8825     * empty ("") after the trim or if it is {@code null}.
    8826     *
    8827     * <p>The String is trimmed using {@link String#trim()}.
    8828     * Trim removes start and end characters &lt;= 32.
    8829     * To strip whitespace use {@link #stripToNull(String)}.
    8830     *
    8831     * <pre>
    8832     * StringUtils.trimToNull(null)          = null
    8833     * StringUtils.trimToNull("")            = null
    8834     * StringUtils.trimToNull("     ")       = null
    8835     * StringUtils.trimToNull("abc")         = "abc"
    8836     * StringUtils.trimToNull("    abc    ") = "abc"
    8837     * </pre>
    8838     *
    8839     * @param str  the String to be trimmed, may be null
    8840     * @return the trimmed String,
    8841     *  {@code null} if only chars &lt;= 32, empty or null String input
    8842     * @since 2.0
    8843     */
    8844    public static String trimToNull(final String str) {
    8845        final String ts = trim(str);
    8846        return isEmpty(ts) ? null : ts;
    8847    }
    8848
    8849    /**
    8850     * Truncates a String. This will turn
    8851     * "Now is the time for all good men" into "Now is the time for".
    8852     *
    8853     * <p>Specifically:</p>
    8854     * <ul>
    8855     *   <li>If {@code str} is less than {@code maxWidth} characters
    8856     *       long, return it.</li>
    8857     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
    8858     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    8859     *       {@link IllegalArgumentException}.</li>
    8860     *   <li>In no case will it return a String of length greater than
    8861     *       {@code maxWidth}.</li>
    8862     * </ul>
    8863     *
    8864     * <pre>
    8865     * StringUtils.truncate(null, 0)       = null
    8866     * StringUtils.truncate(null, 2)       = null
    8867     * StringUtils.truncate("", 4)         = ""
    8868     * StringUtils.truncate("abcdefg", 4)  = "abcd"
    8869     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
    8870     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
    8871     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
    8872     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
    8873     * </pre>
    8874     *
    8875     * @param str  the String to truncate, may be null
    8876     * @param maxWidth  maximum length of result String, must be positive
    8877     * @return truncated String, {@code null} if null String input
    8878     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
    8879     * @since 3.5
    8880     */
    8881    public static String truncate(final String str, final int maxWidth) {
    8882        return truncate(str, 0, maxWidth);
    8883    }
    8884
    8885    /**
    8886     * Truncates a String. This will turn
    8887     * "Now is the time for all good men" into "is the time for all".
    8888     *
    8889     * <p>Works like {@code truncate(String, int)}, but allows you to specify
    8890     * a "left edge" offset.
    8891     *
    8892     * <p>Specifically:</p>
    8893     * <ul>
    8894     *   <li>If {@code str} is less than {@code maxWidth} characters
    8895     *       long, return it.</li>
    8896     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
    8897     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    8898     *       {@link IllegalArgumentException}.</li>
    8899     *   <li>If {@code offset} is less than {@code 0}, throw an
    8900     *       {@link IllegalArgumentException}.</li>
    8901     *   <li>In no case will it return a String of length greater than
    8902     *       {@code maxWidth}.</li>
    8903     * </ul>
    8904     *
    8905     * <pre>
    8906     * StringUtils.truncate(null, 0, 0) = null
    8907     * StringUtils.truncate(null, 2, 4) = null
    8908     * StringUtils.truncate("", 0, 10) = ""
    8909     * StringUtils.truncate("", 2, 10) = ""
    8910     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
    8911     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
    8912     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
    8913     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
    8914     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
    8915     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
    8916     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
    8917     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
    8918     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
    8919     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
    8920     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
    8921     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
    8922     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
    8923     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
    8924     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
    8925     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
    8926     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
    8927     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
    8928     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
    8929     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
    8930     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
    8931     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
    8932     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
    8933     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
    8934     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
    8935     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
    8936     * </pre>
    8937     *
    8938     * @param str  the String to truncate, may be null
    8939     * @param offset  left edge of source String
    8940     * @param maxWidth  maximum length of result String, must be positive
    8941     * @return truncated String, {@code null} if null String input
    8942     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
    8943     * @since 3.5
    8944     */
    8945    public static String truncate(final String str, final int offset, final int maxWidth) {
    8946        if (offset < 0) {
    8947            throw new IllegalArgumentException("offset cannot be negative");
    8948        }
    8949        if (maxWidth < 0) {
    8950            throw new IllegalArgumentException("maxWith cannot be negative");
    8951        }
    8952        if (str == null) {
    8953            return null;
    8954        }
    8955        if (offset > str.length()) {
    8956            return EMPTY;
    8957        }
    8958        if (str.length() > maxWidth) {
    8959            final int ix = Math.min(offset + maxWidth, str.length());
    8960            return str.substring(offset, ix);
    8961        }
    8962        return str.substring(offset);
    8963    }
    8964
    8965    /**
    8966     * Uncapitalizes a String, changing the first character to lower case as
    8967     * per {@link Character#toLowerCase(int)}. No other characters are changed.
    8968     *
    8969     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
    8970     * A {@code null} input String returns {@code null}.</p>
    8971     *
    8972     * <pre>
    8973     * StringUtils.uncapitalize(null)  = null
    8974     * StringUtils.uncapitalize("")    = ""
    8975     * StringUtils.uncapitalize("cat") = "cat"
    8976     * StringUtils.uncapitalize("Cat") = "cat"
    8977     * StringUtils.uncapitalize("CAT") = "cAT"
    8978     * </pre>
    8979     *
    8980     * @param str the String to uncapitalize, may be null
    8981     * @return the uncapitalized String, {@code null} if null String input
    8982     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
    8983     * @see #capitalize(String)
    8984     * @since 2.0
    8985     */
    8986    public static String uncapitalize(final String str) {
    8987        final int strLen = length(str);
    8988        if (strLen == 0) {
    8989            return str;
    8990        }
    8991        final int firstCodePoint = str.codePointAt(0);
    8992        final int newCodePoint = Character.toLowerCase(firstCodePoint);
    8993        if (firstCodePoint == newCodePoint) {
    8994            // already uncapitalized
    8995            return str;
    8996        }
    8997        final int[] newCodePoints = str.codePoints().toArray();
    8998        newCodePoints[0] = newCodePoint; // copy the first code point
    8999        return new String(newCodePoints, 0, newCodePoints.length);
    9000    }
    9001
    9002    /**
    9003     * Unwraps a given string from a character.
    9004     *
    9005     * <pre>
    9006     * StringUtils.unwrap(null, null)         = null
    9007     * StringUtils.unwrap(null, '\0')         = null
    9008     * StringUtils.unwrap(null, '1')          = null
    9009     * StringUtils.unwrap("a", 'a')           = "a"
    9010     * StringUtils.unwrap("aa", 'a')           = ""
    9011     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
    9012     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
    9013     * StringUtils.unwrap("A", '#')           = "A"
    9014     * StringUtils.unwrap("#A", '#')          = "#A"
    9015     * StringUtils.unwrap("A#", '#')          = "A#"
    9016     * </pre>
    9017     *
    9018     * @param str
    9019     *          the String to be unwrapped, can be null
    9020     * @param wrapChar
    9021     *          the character used to unwrap
    9022     * @return unwrapped String or the original string
    9023     *          if it is not quoted properly with the wrapChar
    9024     * @since 3.6
    9025     */
    9026    public static String unwrap(final String str, final char wrapChar) {
    9027        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
    9028            return str;
    9029        }
    9030
    9031        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
    9032            final int startIndex = 0;
    9033            final int endIndex = str.length() - 1;
    9034
    9035            return str.substring(startIndex + 1, endIndex);
    9036        }
    9037
    9038        return str;
    9039    }
    9040
    9041    /**
    9042     * Unwraps a given string from another string.
    9043     *
    9044     * <pre>
    9045     * StringUtils.unwrap(null, null)         = null
    9046     * StringUtils.unwrap(null, "")           = null
    9047     * StringUtils.unwrap(null, "1")          = null
    9048     * StringUtils.unwrap("a", "a")           = "a"
    9049     * StringUtils.unwrap("aa", "a")          = ""
    9050     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
    9051     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
    9052     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
    9053     * StringUtils.unwrap("A", "#")           = "A"
    9054     * StringUtils.unwrap("#A", "#")          = "#A"
    9055     * StringUtils.unwrap("A#", "#")          = "A#"
    9056     * </pre>
    9057     *
    9058     * @param str
    9059     *          the String to be unwrapped, can be null
    9060     * @param wrapToken
    9061     *          the String used to unwrap
    9062     * @return unwrapped String or the original string
    9063     *          if it is not quoted properly with the wrapToken
    9064     * @since 3.6
    9065     */
    9066    public static String unwrap(final String str, final String wrapToken) {
    9067        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
    9068            return str;
    9069        }
    9070
    9071        if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
    9072            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
    9073        }
    9074
    9075        return str;
    9076    }
    9077
    9078    /**
    9079     * Converts a String to upper case as per {@link String#toUpperCase()}.
    9080     *
    9081     * <p>A {@code null} input String returns {@code null}.</p>
    9082     *
    9083     * <pre>
    9084     * StringUtils.upperCase(null)  = null
    9085     * StringUtils.upperCase("")    = ""
    9086     * StringUtils.upperCase("aBc") = "ABC"
    9087     * </pre>
    9088     *
    9089     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
    9090     * the result of this method is affected by the current locale.
    9091     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
    9092     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    9093     *
    9094     * @param str  the String to upper case, may be null
    9095     * @return the upper-cased String, {@code null} if null String input
    9096     */
    9097    public static String upperCase(final String str) {
    9098        if (str == null) {
    9099            return null;
    9100        }
    9101        return str.toUpperCase();
    9102    }
    9103
    9104    /**
    9105     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
    9106     *
    9107     * <p>A {@code null} input String returns {@code null}.</p>
    9108     *
    9109     * <pre>
    9110     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    9111     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    9112     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    9113     * </pre>
    9114     *
    9115     * @param str  the String to upper case, may be null
    9116     * @param locale  the locale that defines the case transformation rules, must not be null
    9117     * @return the upper-cased String, {@code null} if null String input
    9118     * @since 2.5
    9119     */
    9120    public static String upperCase(final String str, final Locale locale) {
    9121        if (str == null) {
    9122            return null;
    9123        }
    9124        return str.toUpperCase(LocaleUtils.toLocale(locale));
    9125    }
    9126
    9127    /**
    9128     * Returns the string representation of the {@code char} array or null.
    9129     *
    9130     * @param value the character array.
    9131     * @return a String or null
    9132     * @see String#valueOf(char[])
    9133     * @since 3.9
    9134     */
    9135    public static String valueOf(final char[] value) {
    9136        return value == null ? null : String.valueOf(value);
    9137    }
    9138
    9139    /**
    9140     * Wraps a string with a char.
    9141     *
    9142     * <pre>
    9143     * StringUtils.wrap(null, *)        = null
    9144     * StringUtils.wrap("", *)          = ""
    9145     * StringUtils.wrap("ab", '\0')     = "ab"
    9146     * StringUtils.wrap("ab", 'x')      = "xabx"
    9147     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9148     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
    9149     * </pre>
    9150     *
    9151     * @param str
    9152     *            the string to be wrapped, may be {@code null}
    9153     * @param wrapWith
    9154     *            the char that will wrap {@code str}
    9155     * @return the wrapped string, or {@code null} if {@code str == null}
    9156     * @since 3.4
    9157     */
    9158    public static String wrap(final String str, final char wrapWith) {
    9159
    9160        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9161            return str;
    9162        }
    9163
    9164        return wrapWith + str + wrapWith;
    9165    }
    9166
    9167    /**
    9168     * Wraps a String with another String.
    9169     *
    9170     * <p>
    9171     * A {@code null} input String returns {@code null}.
    9172     * </p>
    9173     *
    9174     * <pre>
    9175     * StringUtils.wrap(null, *)         = null
    9176     * StringUtils.wrap("", *)           = ""
    9177     * StringUtils.wrap("ab", null)      = "ab"
    9178     * StringUtils.wrap("ab", "x")       = "xabx"
    9179     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9180     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
    9181     * StringUtils.wrap("ab", "'")       = "'ab'"
    9182     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
    9183     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9184     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9185     * </pre>
    9186     *
    9187     * @param str
    9188     *            the String to be wrapper, may be null
    9189     * @param wrapWith
    9190     *            the String that will wrap str
    9191     * @return wrapped String, {@code null} if null String input
    9192     * @since 3.4
    9193     */
    9194    public static String wrap(final String str, final String wrapWith) {
    9195
    9196        if (isEmpty(str) || isEmpty(wrapWith)) {
    9197            return str;
    9198        }
    9199
    9200        return wrapWith.concat(str).concat(wrapWith);
    9201    }
    9202
    9203    /**
    9204     * Wraps a string with a char if that char is missing from the start or end of the given string.
    9205     *
    9206     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
    9207     *
    9208     * <pre>
    9209     * StringUtils.wrapIfMissing(null, *)        = null
    9210     * StringUtils.wrapIfMissing("", *)          = ""
    9211     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
    9212     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
    9213     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
    9214     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
    9215     * StringUtils.wrapIfMissing("/", '/')  = "/"
    9216     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
    9217     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
    9218     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
    9219     * </pre>
    9220     *
    9221     * @param str
    9222     *            the string to be wrapped, may be {@code null}
    9223     * @param wrapWith
    9224     *            the char that will wrap {@code str}
    9225     * @return the wrapped string, or {@code null} if {@code str == null}
    9226     * @since 3.5
    9227     */
    9228    public static String wrapIfMissing(final String str, final char wrapWith) {
    9229        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9230            return str;
    9231        }
    9232        final boolean wrapStart = str.charAt(0) != wrapWith;
    9233        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
    9234        if (!wrapStart && !wrapEnd) {
    9235            return str;
    9236        }
    9237
    9238        final StringBuilder builder = new StringBuilder(str.length() + 2);
    9239        if (wrapStart) {
    9240            builder.append(wrapWith);
    9241        }
    9242        builder.append(str);
    9243        if (wrapEnd) {
    9244            builder.append(wrapWith);
    9245        }
    9246        return builder.toString();
    9247    }
    9248
    9249    /**
    9250     * Wraps a string with a string if that string is missing from the start or end of the given string.
    9251     *
    9252     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
    9253     *
    9254     * <pre>
    9255     * StringUtils.wrapIfMissing(null, *)         = null
    9256     * StringUtils.wrapIfMissing("", *)           = ""
    9257     * StringUtils.wrapIfMissing("ab", null)      = "ab"
    9258     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
    9259     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
    9260     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
    9261     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
    9262     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
    9263     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
    9264     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
    9265     * StringUtils.wrapIfMissing("/", "/")  = "/"
    9266     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
    9267     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
    9268     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
    9269     * </pre>
    9270     *
    9271     * @param str
    9272     *            the string to be wrapped, may be {@code null}
    9273     * @param wrapWith
    9274     *            the string that will wrap {@code str}
    9275     * @return the wrapped string, or {@code null} if {@code str == null}
    9276     * @since 3.5
    9277     */
    9278    public static String wrapIfMissing(final String str, final String wrapWith) {
    9279        if (isEmpty(str) || isEmpty(wrapWith)) {
    9280            return str;
    9281        }
    9282
    9283        final boolean wrapStart = !str.startsWith(wrapWith);
    9284        final boolean wrapEnd = !str.endsWith(wrapWith);
    9285        if (!wrapStart && !wrapEnd) {
    9286            return str;
    9287        }
    9288
    9289        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
    9290        if (wrapStart) {
    9291            builder.append(wrapWith);
    9292        }
    9293        builder.append(str);
    9294        if (wrapEnd) {
    9295            builder.append(wrapWith);
    9296        }
    9297        return builder.toString();
    9298    }
    9299
    9300    /**
    9301     * {@link StringUtils} instances should NOT be constructed in
    9302     * standard programming. Instead, the class should be used as
    9303     * {@code StringUtils.trim(" foo ");}.
    9304     *
    9305     * <p>This constructor is public to permit tools that require a JavaBean
    9306     * instance to operate.</p>
    9307     *
    9308     * @deprecated TODO Make private in 4.0.
    9309     */
    9310    @Deprecated
    9311    public StringUtils() {
    9312        // empty
    9313    }
    9314
    9315}