    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 *      http://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.charset.Charset;
    021import java.text.Normalizer;
    022import java.util.ArrayList;
    023import java.util.Arrays;
    024import java.util.HashSet;
    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;
    032
    033import org.apache.commons.lang3.function.Suppliers;
    034import org.apache.commons.lang3.function.ToBooleanBiFunction;
    035import org.apache.commons.lang3.stream.LangCollectors;
    036import org.apache.commons.lang3.stream.Streams;
    037
    038/**
    039 * Operations on {@link java.lang.String} that are
    040 * {@code null} safe.
    041 *
    042 * <ul>
    043 *  <li><b>IsEmpty/IsBlank</b>
    044 *      - checks if a String contains text</li>
    045 *  <li><b>Trim/Strip</b>
    046 *      - removes leading and trailing whitespace</li>
    047 *  <li><b>Equals/Compare</b>
    048 *      - compares two strings in a null-safe manner</li>
    049 *  <li><b>startsWith</b>
    050 *      - check if a String starts with a prefix in a null-safe manner</li>
    051 *  <li><b>endsWith</b>
    052 *      - check if a String ends with a suffix in a null-safe manner</li>
    053 *  <li><b>IndexOf/LastIndexOf/Contains</b>
    054 *      - null-safe index-of checks
    055 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
    056 *      - index-of any of a set of Strings</li>
    057 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
    058 *      - checks if String contains only/none/any of these characters</li>
    059 *  <li><b>Substring/Left/Right/Mid</b>
    060 *      - null-safe substring extractions</li>
    061 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
    062 *      - substring extraction relative to other strings</li>
    063 *  <li><b>Split/Join</b>
    064 *      - splits a String into an array of substrings and vice versa</li>
    065 *  <li><b>Remove/Delete</b>
    066 *      - removes part of a String</li>
    067 *  <li><b>Replace/Overlay</b>
    068 *      - Searches a String and replaces one String with another</li>
    069 *  <li><b>Chomp/Chop</b>
    070 *      - removes the last part of a String</li>
    071 *  <li><b>AppendIfMissing</b>
    072 *      - appends a suffix to the end of the String if not present</li>
    073 *  <li><b>PrependIfMissing</b>
    074 *      - prepends a prefix to the start of the String if not present</li>
    075 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
    076 *      - pads a String</li>
    077 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
    078 *      - changes the case of a String</li>
    079 *  <li><b>CountMatches</b>
    080 *      - counts the number of occurrences of one String in another</li>
    081 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
    082 *      - checks the characters in a String</li>
    083 *  <li><b>DefaultString</b>
    084 *      - protects against a null input String</li>
    085 *  <li><b>Rotate</b>
    086 *      - rotate (circular shift) a String</li>
    087 *  <li><b>Reverse/ReverseDelimited</b>
    088 *      - reverses a String</li>
    089 *  <li><b>Abbreviate</b>
    090 *      - abbreviates a string using ellipses or another given String</li>
    091 *  <li><b>Difference</b>
    092 *      - compares Strings and reports on their differences</li>
    093 *  <li><b>LevenshteinDistance</b>
    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     * A String for a space character.
    145     *
    146     * @since 3.2
    147     */
    148    public static final String SPACE = " ";
    149
    150    /**
    151     * The empty String {@code ""}.
    152     * @since 2.0
    153     */
    154    public static final String EMPTY = "";
    155
    156    /**
    157     * A String for linefeed LF ("\n").
    158     *
    159     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    160     *      for Character and String Literals</a>
    161     * @since 3.2
    162     */
    163    public static final String LF = "\n";
    164
    165    /**
    166     * A String for carriage return CR ("\r").
    167     *
    168     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    169     *      for Character and String Literals</a>
    170     * @since 3.2
    171     */
    172    public static final String CR = "\r";
    173
    174    /**
    175     * Represents a failed index search.
    176     * @since 2.1
    177     */
    178    public static final int INDEX_NOT_FOUND = -1;
    179
    180    /**
    181     * The maximum size to which the padding constant(s) can expand.
    182     */
    183    private static final int PAD_LIMIT = 8192;
    184
    185    /**
    186     * Pattern used in {@link #stripAccents(String)}.
    187     */
    188    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
    189
    190    /**
    191     * Abbreviates a String using ellipses. This will turn
    192     * "Now is the time for all good men" into "Now is the time for..."
    193     *
    194     * <p>Specifically:</p>
    195     * <ul>
    196     *   <li>If the number of characters in {@code str} is less than or equal to
    197     *       {@code maxWidth}, return {@code str}.</li>
    198     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
    199     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
    200     *       {@link IllegalArgumentException}.</li>
    201     *   <li>In no case will it return a String of length greater than
    202     *       {@code maxWidth}.</li>
    203     * </ul>
    204     *
    205     * <pre>
    206     * StringUtils.abbreviate(null, *)      = null
    207     * StringUtils.abbreviate("", 4)        = ""
    208     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
    209     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
    210     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
    211     * StringUtils.abbreviate("abcdefg", 4) = "a..."
    212     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
    213     * </pre>
    214     *
    215     * @param str  the String to check, may be null
    216     * @param maxWidth  maximum length of result String, must be at least 4
    217     * @return abbreviated String, {@code null} if null String input
    218     * @throws IllegalArgumentException if the width is too small
    219     * @since 2.0
    220     */
    221    public static String abbreviate(final String str, final int maxWidth) {
    222        return abbreviate(str, "...", 0, maxWidth);
    223    }
    224
    225    /**
    226     * Abbreviates a String using ellipses. This will turn
    227     * "Now is the time for all good men" into "...is the time for..."
    228     *
    229     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
    230     * a "left edge" offset.  Note that this left edge is not necessarily going to
    231     * be the leftmost character in the result, or the first character following the
    232     * ellipses, but it will appear somewhere in the result.
    233     *
    234     * <p>In no case will it return a String of length greater than
    235     * {@code maxWidth}.</p>
    236     *
    237     * <pre>
    238     * StringUtils.abbreviate(null, *, *)                = null
    239     * StringUtils.abbreviate("", 0, 4)                  = ""
    240     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
    241     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
    242     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
    243     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
    244     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
    245     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
    246     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
    247     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
    248     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
    249     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
    250     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
    251     * </pre>
    252     *
    253     * @param str  the String to check, may be null
    254     * @param offset  left edge of source String
    255     * @param maxWidth  maximum length of result String, must be at least 4
    256     * @return abbreviated String, {@code null} if null String input
    257     * @throws IllegalArgumentException if the width is too small
    258     * @since 2.0
    259     */
    260    public static String abbreviate(final String str, final int offset, final int maxWidth) {
    261        return abbreviate(str, "...", offset, maxWidth);
    262    }
    263
    264    /**
    265     * Abbreviates a String using another given String as replacement marker. This will turn
    266     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
    267     * as the replacement marker.
    268     *
    269     * <p>Specifically:</p>
    270     * <ul>
    271     *   <li>If the number of characters in {@code str} is less than or equal to
    272     *       {@code maxWidth}, return {@code str}.</li>
    273     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
    274     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
    275     *       {@link IllegalArgumentException}.</li>
    276     *   <li>In no case will it return a String of length greater than
    277     *       {@code maxWidth}.</li>
    278     * </ul>
    279     *
    280     * <pre>
    281     * StringUtils.abbreviate(null, "...", *)      = null
    282     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
    283     * StringUtils.abbreviate("", "...", 4)        = ""
    284     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
    285     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
    286     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
    287     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
    288     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
    289     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
    290     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
    291     * </pre>
    292     *
    293     * @param str  the String to check, may be null
    294     * @param abbrevMarker  the String used as replacement marker
    295     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
    296     * @return abbreviated String, {@code null} if null String input
    297     * @throws IllegalArgumentException if the width is too small
    298     * @since 3.6
    299     */
    300    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
    301        return abbreviate(str, abbrevMarker, 0, maxWidth);
    302    }
    303    /**
    304     * Abbreviates a String using a given replacement marker. This will turn
    305     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
    306     * as the replacement marker.
    307     *
    308     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
    309     * a "left edge" offset.  Note that this left edge is not necessarily going to
    310     * be the leftmost character in the result, or the first character following the
    311     * replacement marker, but it will appear somewhere in the result.
    312     *
    313     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
    314     *
    315     * <pre>
    316     * StringUtils.abbreviate(null, null, *, *)                 = null
    317     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
    318     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
    319     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
    320     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
    321     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
    322     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
    323     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
    324     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
    325     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
    326     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
    327     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
    328     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
    329     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
    330     * </pre>
    331     *
    332     * @param str  the String to check, may be null
    333     * @param abbrevMarker  the String used as replacement marker
    334     * @param offset  left edge of source String
    335     * @param maxWidth  maximum length of result String, must be at least 4
    336     * @return abbreviated String, {@code null} if null String input
    337     * @throws IllegalArgumentException if the width is too small
    338     * @since 3.6
    339     */
    340    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
    341        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
    342            return substring(str, 0, maxWidth);
    343        }
    344        if (isAnyEmpty(str, abbrevMarker)) {
    345            return str;
    346        }
    347        final int abbrevMarkerLength = abbrevMarker.length();
    348        final int minAbbrevWidth = abbrevMarkerLength + 1;
    349        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
    350
    351        if (maxWidth < minAbbrevWidth) {
    352            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
    353        }
    354        final int strLen = str.length();
    355        if (strLen <= maxWidth) {
    356            return str;
    357        }
    358        if (offset > strLen) {
    359            offset = strLen;
    360        }
    361        if (strLen - offset < maxWidth - abbrevMarkerLength) {
    362            offset = strLen - (maxWidth - abbrevMarkerLength);
    363        }
    364        if (offset <= abbrevMarkerLength+1) {
    365            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
    366        }
    367        if (maxWidth < minAbbrevWidthOffset) {
    368            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
    369        }
    370        if (offset + maxWidth - abbrevMarkerLength < strLen) {
    371            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
    372        }
    373        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
    374    }
    375
    376    /**
    377     * Abbreviates a String to the length passed, replacing the middle characters with the supplied
    378     * replacement String.
    379     *
    380     * <p>This abbreviation only occurs if the following criteria is met:</p>
    381     * <ul>
    382     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
    383     * <li>The length to truncate to is less than the length of the supplied String</li>
    384     * <li>The length to truncate to is greater than 0</li>
    385     * <li>The abbreviated String will have enough room for the length supplied replacement String
    386     * and the first and last characters of the supplied String for abbreviation</li>
    387     * </ul>
    388     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
    389     * </p>
    390     *
    391     * <pre>
    392     * StringUtils.abbreviateMiddle(null, null, 0)      = null
    393     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
    394     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
    395     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
    396     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
    397     * </pre>
    398     *
    399     * @param str  the String to abbreviate, may be null
    400     * @param middle the String to replace the middle characters with, may be null
    401     * @param length the length to abbreviate {@code str} to.
    402     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
    403     * @since 2.5
    404     */
    405    public static String abbreviateMiddle(final String str, final String middle, final int length) {
    406        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length()+2) {
    407            return str;
    408        }
    409
    410        final int targetSting = length-middle.length();
    411        final int startOffset = targetSting/2+targetSting%2;
    412        final int endOffset = str.length()-targetSting/2;
    413
    414        return str.substring(0, startOffset) +
    415            middle +
    416            str.substring(endOffset);
    417    }
    418
    419    /**
    420     * Appends the suffix to the end of the string if the string does not
    421     * already end with the suffix.
    422     *
    423     * @param str The string.
    424     * @param suffix The suffix to append to the end of the string.
    425     * @param ignoreCase Indicates whether the compare should ignore case.
    426     * @param suffixes Additional suffixes that are valid terminators (optional).
    427     *
    428     * @return A new String if suffix was appended, the same string otherwise.
    429     */
    430    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
    431        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
    432            return str;
    433        }
    434        if (ArrayUtils.isNotEmpty(suffixes)) {
    435            for (final CharSequence s : suffixes) {
    436                if (endsWith(str, s, ignoreCase)) {
    437                    return str;
    438                }
    439            }
    440        }
    441        return str + suffix.toString();
    442    }
    443
    444    /**
    445     * Appends the suffix to the end of the string if the string does not
    446     * already end with any of the suffixes.
    447     *
    448     * <pre>
    449     * StringUtils.appendIfMissing(null, null) = null
    450     * StringUtils.appendIfMissing("abc", null) = "abc"
    451     * StringUtils.appendIfMissing("", "xyz") = "xyz"
    452     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
    453     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
    454     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
    455     * </pre>
    456     * <p>With additional suffixes,</p>
    457     * <pre>
    458     * StringUtils.appendIfMissing(null, null, null) = null
    459     * StringUtils.appendIfMissing("abc", null, null) = "abc"
    460     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
    461     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    462     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
    463     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
    464     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
    465     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
    466     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
    467     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
    468     * </pre>
    469     *
    470     * @param str The string.
    471     * @param suffix The suffix to append to the end of the string.
    472     * @param suffixes Additional suffixes that are valid terminators.
    473     *
    474     * @return A new String if suffix was appended, the same string otherwise.
    475     *
    476     * @since 3.2
    477     */
    478    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    479        return appendIfMissing(str, suffix, false, suffixes);
    480    }
    481
    482    /**
    483     * Appends the suffix to the end of the string if the string does not
    484     * already end, case-insensitive, with any of the suffixes.
    485     *
    486     * <pre>
    487     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
    488     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
    489     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
    490     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
    491     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
    492     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
    493     * </pre>
    494     * <p>With additional suffixes,</p>
    495     * <pre>
    496     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
    497     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
    498     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
    499     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    500     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    501     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "abcxyz"
    502     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
    503     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
    504     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
    505     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
    506     * </pre>
    507     *
    508     * @param str The string.
    509     * @param suffix The suffix to append to the end of the string.
    510     * @param suffixes Additional suffixes that are valid terminators.
    511     *
    512     * @return A new String if suffix was appended, the same string otherwise.
    513     *
    514     * @since 3.2
    515     */
    516    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    517        return appendIfMissing(str, suffix, true, suffixes);
    518    }
    519
    520    /**
    521     * Capitalizes a String changing the first character to title case as
    522     * per {@link Character#toTitleCase(int)}. No other characters are changed.
    523     *
    524     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
    525     * A {@code null} input String returns {@code null}.</p>
    526     *
    527     * <pre>
    528     * StringUtils.capitalize(null)  = null
    529     * StringUtils.capitalize("")    = ""
    530     * StringUtils.capitalize("cat") = "Cat"
    531     * StringUtils.capitalize("cAt") = "CAt"
    532     * StringUtils.capitalize("'cat'") = "'cat'"
    533     * </pre>
    534     *
    535     * @param str the String to capitalize, may be null
    536     * @return the capitalized String, {@code null} if null String input
    537     * @see org.apache.commons.text.WordUtils#capitalize(String)
    538     * @see #uncapitalize(String)
    539     * @since 2.0
    540     */
    541    public static String capitalize(final String str) {
    542        final int strLen = length(str);
    543        if (strLen == 0) {
    544            return str;
    545        }
    546
    547        final int firstCodepoint = str.codePointAt(0);
    548        final int newCodePoint = Character.toTitleCase(firstCodepoint);
    549        if (firstCodepoint == newCodePoint) {
    550            // already capitalized
    551            return str;
    552        }
    553
    554        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    555        int outOffset = 0;
    556        newCodePoints[outOffset++] = newCodePoint; // copy the first code point
    557        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
    558            final int codePoint = str.codePointAt(inOffset);
    559            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
    560            inOffset += Character.charCount(codePoint);
    561         }
    562        return new String(newCodePoints, 0, outOffset);
    563    }
    564
    565    /**
    566     * Centers a String in a larger String of size {@code size}
    567     * using the space character (' ').
    568     *
    569     * <p>If the size is less than the String length, the original String is returned.
    570     * A {@code null} String returns {@code null}.
    571     * A negative size is treated as zero.</p>
    572     *
    573     * <p>Equivalent to {@code center(str, size, " ")}.</p>
    574     *
    575     * <pre>
    576     * StringUtils.center(null, *)   = null
    577     * StringUtils.center("", 4)     = "    "
    578     * StringUtils.center("ab", -1)  = "ab"
    579     * StringUtils.center("ab", 4)   = " ab "
    580     * StringUtils.center("abcd", 2) = "abcd"
    581     * StringUtils.center("a", 4)    = " a  "
    582     * </pre>
    583     *
    584     * @param str  the String to center, may be null
    585     * @param size  the int size of new String, negative treated as zero
    586     * @return centered String, {@code null} if null String input
    587     */
    588    public static String center(final String str, final int size) {
    589        return center(str, size, ' ');
    590    }
    591
    592    /**
    593     * Centers a String in a larger String of size {@code size}.
    594     * Uses a supplied character as the value to pad the String with.
    595     *
    596     * <p>If the size is less than the String length, the String is returned.
    597     * A {@code null} String returns {@code null}.
    598     * A negative size is treated as zero.</p>
    599     *
    600     * <pre>
    601     * StringUtils.center(null, *, *)     = null
    602     * StringUtils.center("", 4, ' ')     = "    "
    603     * StringUtils.center("ab", -1, ' ')  = "ab"
    604     * StringUtils.center("ab", 4, ' ')   = " ab "
    605     * StringUtils.center("abcd", 2, ' ') = "abcd"
    606     * StringUtils.center("a", 4, ' ')    = " a  "
    607     * StringUtils.center("a", 4, 'y')    = "yayy"
    608     * </pre>
    609     *
    610     * @param str  the String to center, may be null
    611     * @param size  the int size of new String, negative treated as zero
    612     * @param padChar  the character to pad the new String with
    613     * @return centered String, {@code null} if null String input
    614     * @since 2.0
    615     */
    616    public static String center(String str, final int size, final char padChar) {
    617        if (str == null || size <= 0) {
    618            return str;
    619        }
    620        final int strLen = str.length();
    621        final int pads = size - strLen;
    622        if (pads <= 0) {
    623            return str;
    624        }
    625        str = leftPad(str, strLen + pads / 2, padChar);
    626        str = rightPad(str, size, padChar);
    627        return str;
    628    }
    629
    630    /**
    631     * Centers a String in a larger String of size {@code size}.
    632     * Uses a supplied String as the value to pad the String with.
    633     *
    634     * <p>If the size is less than the String length, the String is returned.
    635     * A {@code null} String returns {@code null}.
    636     * A negative size is treated as zero.</p>
    637     *
    638     * <pre>
    639     * StringUtils.center(null, *, *)     = null
    640     * StringUtils.center("", 4, " ")     = "    "
    641     * StringUtils.center("ab", -1, " ")  = "ab"
    642     * StringUtils.center("ab", 4, " ")   = " ab "
    643     * StringUtils.center("abcd", 2, " ") = "abcd"
    644     * StringUtils.center("a", 4, " ")    = " a  "
    645     * StringUtils.center("a", 4, "yz")   = "yayz"
    646     * StringUtils.center("abc", 7, null) = "  abc  "
    647     * StringUtils.center("abc", 7, "")   = "  abc  "
    648     * </pre>
    649     *
    650     * @param str  the String to center, may be null
    651     * @param size  the int size of new String, negative treated as zero
    652     * @param padStr  the String to pad the new String with, must not be null or empty
    653     * @return centered String, {@code null} if null String input
    654     * @throws IllegalArgumentException if padStr is {@code null} or empty
    655     */
    656    public static String center(String str, final int size, String padStr) {
    657        if (str == null || size <= 0) {
    658            return str;
    659        }
    660        if (isEmpty(padStr)) {
    661            padStr = SPACE;
    662        }
    663        final int strLen = str.length();
    664        final int pads = size - strLen;
    665        if (pads <= 0) {
    666            return str;
    667        }
    668        str = leftPad(str, strLen + pads / 2, padStr);
    669        str = rightPad(str, size, padStr);
    670        return str;
    671    }
    672
    673    /**
    674     * Removes one newline from end of a String if it's there,
    675     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
    676     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
    677     *
    678     * <p>NOTE: This method changed in 2.0.
    679     * It now more closely matches Perl chomp.</p>
    680     *
    681     * <pre>
    682     * StringUtils.chomp(null)          = null
    683     * StringUtils.chomp("")            = ""
    684     * StringUtils.chomp("abc \r")      = "abc "
    685     * StringUtils.chomp("abc\n")       = "abc"
    686     * StringUtils.chomp("abc\r\n")     = "abc"
    687     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
    688     * StringUtils.chomp("abc\n\r")     = "abc\n"
    689     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
    690     * StringUtils.chomp("\r")          = ""
    691     * StringUtils.chomp("\n")          = ""
    692     * StringUtils.chomp("\r\n")        = ""
    693     * </pre>
    694     *
    695     * @param str  the String to chomp a newline from, may be null
    696     * @return String without newline, {@code null} if null String input
    697     */
    698    public static String chomp(final String str) {
    699        if (isEmpty(str)) {
    700            return str;
    701        }
    702
    703        if (str.length() == 1) {
    704            final char ch = str.charAt(0);
    705            if (ch == CharUtils.CR || ch == CharUtils.LF) {
    706                return EMPTY;
    707            }
    708            return str;
    709        }
    710
    711        int lastIdx = str.length() - 1;
    712        final char last = str.charAt(lastIdx);
    713
    714        if (last == CharUtils.LF) {
    715            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    716                lastIdx--;
    717            }
    718        } else if (last != CharUtils.CR) {
    719            lastIdx++;
    720        }
    721        return str.substring(0, lastIdx);
    722    }
    723
    724    /**
    725     * Removes {@code separator} from the end of
    726     * {@code str} if it's there, otherwise leave it alone.
    727     *
    728     * <p>NOTE: This method changed in version 2.0.
    729     * It now more closely matches Perl chomp.
    730     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
    731     * This method uses {@link String#endsWith(String)}.</p>
    732     *
    733     * <pre>
    734     * StringUtils.chomp(null, *)         = null
    735     * StringUtils.chomp("", *)           = ""
    736     * StringUtils.chomp("foobar", "bar") = "foo"
    737     * StringUtils.chomp("foobar", "baz") = "foobar"
    738     * StringUtils.chomp("foo", "foo")    = ""
    739     * StringUtils.chomp("foo ", "foo")   = "foo "
    740     * StringUtils.chomp(" foo", "foo")   = " "
    741     * StringUtils.chomp("foo", "foooo")  = "foo"
    742     * StringUtils.chomp("foo", "")       = "foo"
    743     * StringUtils.chomp("foo", null)     = "foo"
    744     * </pre>
    745     *
    746     * @param str  the String to chomp from, may be null
    747     * @param separator  separator String, may be null
    748     * @return String without trailing separator, {@code null} if null String input
    749     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
    750     */
    751    @Deprecated
    752    public static String chomp(final String str, final String separator) {
    753        return removeEnd(str, separator);
    754    }
    755
    756    /**
    757     * Remove the last character from a String.
    758     *
    759     * <p>If the String ends in {@code \r\n}, then remove both
    760     * of them.</p>
    761     *
    762     * <pre>
    763     * StringUtils.chop(null)          = null
    764     * StringUtils.chop("")            = ""
    765     * StringUtils.chop("abc \r")      = "abc "
    766     * StringUtils.chop("abc\n")       = "abc"
    767     * StringUtils.chop("abc\r\n")     = "abc"
    768     * StringUtils.chop("abc")         = "ab"
    769     * StringUtils.chop("abc\nabc")    = "abc\nab"
    770     * StringUtils.chop("a")           = ""
    771     * StringUtils.chop("\r")          = ""
    772     * StringUtils.chop("\n")          = ""
    773     * StringUtils.chop("\r\n")        = ""
    774     * </pre>
    775     *
    776     * @param str  the String to chop last character from, may be null
    777     * @return String without last character, {@code null} if null String input
    778     */
    779    public static String chop(final String str) {
    780        if (str == null) {
    781            return null;
    782        }
    783        final int strLen = str.length();
    784        if (strLen < 2) {
    785            return EMPTY;
    786        }
    787        final int lastIdx = strLen - 1;
    788        final String ret = str.substring(0, lastIdx);
    789        final char last = str.charAt(lastIdx);
    790        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
    791            return ret.substring(0, lastIdx - 1);
    792        }
    793        return ret;
    794    }
    795
    796    /**
    797     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    798     * <ul>
    799     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    800     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    801     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    802     * </ul>
    803     *
    804     * <p>This is a {@code null} safe version of :</p>
    805     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    806     *
    807     * <p>{@code null} value is considered less than non-{@code null} value.
    808     * Two {@code null} references are considered equal.</p>
    809     *
    810     * <pre>
    811     * StringUtils.compare(null, null)   = 0
    812     * StringUtils.compare(null , "a")   &lt; 0
    813     * StringUtils.compare("a", null)    &gt; 0
    814     * StringUtils.compare("abc", "abc") = 0
    815     * StringUtils.compare("a", "b")     &lt; 0
    816     * StringUtils.compare("b", "a")     &gt; 0
    817     * StringUtils.compare("a", "B")     &gt; 0
    818     * StringUtils.compare("ab", "abc")  &lt; 0
    819     * </pre>
    820     *
    821     * @see #compare(String, String, boolean)
    822     * @see String#compareTo(String)
    823     * @param str1  the String to compare from
    824     * @param str2  the String to compare to
    825     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
    826     * @since 3.5
    827     */
    828    public static int compare(final String str1, final String str2) {
    829        return compare(str1, str2, true);
    830    }
    831
    832    /**
    833     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    834     * <ul>
    835     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    836     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    837     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    838     * </ul>
    839     *
    840     * <p>This is a {@code null} safe version of :</p>
    841     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    842     *
    843     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    844     * Two {@code null} references are considered equal.</p>
    845     *
    846     * <pre>
    847     * StringUtils.compare(null, null, *)     = 0
    848     * StringUtils.compare(null , "a", true)  &lt; 0
    849     * StringUtils.compare(null , "a", false) &gt; 0
    850     * StringUtils.compare("a", null, true)   &gt; 0
    851     * StringUtils.compare("a", null, false)  &lt; 0
    852     * StringUtils.compare("abc", "abc", *)   = 0
    853     * StringUtils.compare("a", "b", *)       &lt; 0
    854     * StringUtils.compare("b", "a", *)       &gt; 0
    855     * StringUtils.compare("a", "B", *)       &gt; 0
    856     * StringUtils.compare("ab", "abc", *)    &lt; 0
    857     * </pre>
    858     *
    859     * @see String#compareTo(String)
    860     * @param str1  the String to compare from
    861     * @param str2  the String to compare to
    862     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    863     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
    864     * @since 3.5
    865     */
    866    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
    867        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    868            return 0;
    869        }
    870        if (str1 == null) {
    871            return nullIsLess ? -1 : 1;
    872        }
    873        if (str2 == null) {
    874            return nullIsLess ? 1 : - 1;
    875        }
    876        return str1.compareTo(str2);
    877    }
    878
    879    /**
    880     * Compare two Strings lexicographically, ignoring case differences,
    881     * as per {@link String#compareToIgnoreCase(String)}, returning :
    882     * <ul>
    883     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    884     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    885     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    886     * </ul>
    887     *
    888     * <p>This is a {@code null} safe version of :</p>
    889     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    890     *
    891     * <p>{@code null} value is considered less than non-{@code null} value.
    892     * Two {@code null} references are considered equal.
    893     * Comparison is case insensitive.</p>
    894     *
    895     * <pre>
    896     * StringUtils.compareIgnoreCase(null, null)   = 0
    897     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
    898     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
    899     * StringUtils.compareIgnoreCase("abc", "abc") = 0
    900     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
    901     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
    902     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
    903     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
    904     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
    905     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
    906     * </pre>
    907     *
    908     * @see #compareIgnoreCase(String, String, boolean)
    909     * @see String#compareToIgnoreCase(String)
    910     * @param str1  the String to compare from
    911     * @param str2  the String to compare to
    912     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    913     *          ignoring case differences.
    914     * @since 3.5
    915     */
    916    public static int compareIgnoreCase(final String str1, final String str2) {
    917        return compareIgnoreCase(str1, str2, true);
    918    }
    919
    920    /**
    921     * Compare two Strings lexicographically, ignoring case differences,
    922     * as per {@link String#compareToIgnoreCase(String)}, returning :
    923     * <ul>
    924     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    925     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    926     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    927     * </ul>
    928     *
    929     * <p>This is a {@code null} safe version of :</p>
    930     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    931     *
    932     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    933     * Two {@code null} references are considered equal.
    934     * Comparison is case insensitive.</p>
    935     *
    936     * <pre>
    937     * StringUtils.compareIgnoreCase(null, null, *)     = 0
    938     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
    939     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
    940     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
    941     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
    942     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
    943     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
    944     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
    945     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
    946     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
    947     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
    948     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
    949     * </pre>
    950     *
    951     * @see String#compareToIgnoreCase(String)
    952     * @param str1  the String to compare from
    953     * @param str2  the String to compare to
    954     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    955     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    956     *          ignoring case differences.
    957     * @since 3.5
    958     */
    959    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
    960        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    961            return 0;
    962        }
    963        if (str1 == null) {
    964            return nullIsLess ? -1 : 1;
    965        }
    966        if (str2 == null) {
    967            return nullIsLess ? 1 : - 1;
    968        }
    969        return str1.compareToIgnoreCase(str2);
    970    }
    971
    972    /**
    973     * Checks if CharSequence contains a search CharSequence, handling {@code null}.
    974     * This method uses {@link String#indexOf(String)} if possible.
    975     *
    976     * <p>A {@code null} CharSequence will return {@code false}.</p>
    977     *
    978     * <pre>
    979     * StringUtils.contains(null, *)     = false
    980     * StringUtils.contains(*, null)     = false
    981     * StringUtils.contains("", "")      = true
    982     * StringUtils.contains("abc", "")   = true
    983     * StringUtils.contains("abc", "a")  = true
    984     * StringUtils.contains("abc", "z")  = false
    985     * </pre>
    986     *
    987     * @param seq  the CharSequence to check, may be null
    988     * @param searchSeq  the CharSequence to find, may be null
    989     * @return true if the CharSequence contains the search CharSequence,
    990     *  false if not or {@code null} string input
    991     * @since 2.0
    992     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
    993     */
    994    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
    995        if (seq == null || searchSeq == null) {
    996            return false;
    997        }
    998        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
    999    }
    1000
    1001    /**
    1002     * Checks if CharSequence contains a search character, handling {@code null}.
    1003     * This method uses {@link String#indexOf(int)} if possible.
    1004     *
    1005     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
    1006     *
    1007     * <pre>
    1008     * StringUtils.contains(null, *)    = false
    1009     * StringUtils.contains("", *)      = false
    1010     * StringUtils.contains("abc", 'a') = true
    1011     * StringUtils.contains("abc", 'z') = false
    1012     * </pre>
    1013     *
    1014     * @param seq  the CharSequence to check, may be null
    1015     * @param searchChar  the character to find
    1016     * @return true if the CharSequence contains the search character,
    1017     *  false if not or {@code null} string input
    1018     * @since 2.0
    1019     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
    1020     */
    1021    public static boolean contains(final CharSequence seq, final int searchChar) {
    1022        if (isEmpty(seq)) {
    1023            return false;
    1024        }
    1025        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
    1026    }
    1027
    1028    /**
    1029     * Checks if the CharSequence contains any character in the given
    1030     * set of characters.
    1031     *
    1032     * <p>A {@code null} CharSequence will return {@code false}.
    1033     * A {@code null} or zero length search array will return {@code false}.</p>
    1034     *
    1035     * <pre>
    1036     * StringUtils.containsAny(null, *)                  = false
    1037     * StringUtils.containsAny("", *)                    = false
    1038     * StringUtils.containsAny(*, null)                  = false
    1039     * StringUtils.containsAny(*, [])                    = false
    1040     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    1041     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    1042     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    1043     * StringUtils.containsAny("aba", ['z'])             = false
    1044     * </pre>
    1045     *
    1046     * @param cs  the CharSequence to check, may be null
    1047     * @param searchChars  the chars to search for, may be null
    1048     * @return the {@code true} if any of the chars are found,
    1049     * {@code false} if no match or null input
    1050     * @since 2.4
    1051     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
    1052     */
    1053    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    1054        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1055            return false;
    1056        }
    1057        final int csLength = cs.length();
    1058        final int searchLength = searchChars.length;
    1059        final int csLast = csLength - 1;
    1060        final int searchLast = searchLength - 1;
    1061        for (int i = 0; i < csLength; i++) {
    1062            final char ch = cs.charAt(i);
    1063            for (int j = 0; j < searchLength; j++) {
    1064                if (searchChars[j] == ch) {
    1065                    if (!Character.isHighSurrogate(ch)) {
    1066                        // ch is in the Basic Multilingual Plane
    1067                        return true;
    1068                    }
    1069                    if (j == searchLast) {
    1070                        // missing low surrogate, fine, like String.indexOf(String)
    1071                        return true;
    1072                    }
    1073                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1074                        return true;
    1075                    }
    1076                }
    1077            }
    1078        }
    1079        return false;
    1080    }
    1081
    1082    /**
    1083     * Checks if the CharSequence contains any character in the given set of characters.
    1084     *
    1085     * <p>
    1086     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
    1087     * {@code false}.
    1088     * </p>
    1089     *
    1090     * <pre>
    1091     * StringUtils.containsAny(null, *)               = false
    1092     * StringUtils.containsAny("", *)                 = false
    1093     * StringUtils.containsAny(*, null)               = false
    1094     * StringUtils.containsAny(*, "")                 = false
    1095     * StringUtils.containsAny("zzabyycdxx", "za")    = true
    1096     * StringUtils.containsAny("zzabyycdxx", "by")    = true
    1097     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
    1098     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
    1099     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
    1100     * StringUtils.containsAny("aba", "z")            = false
    1101     * </pre>
    1102     *
    1103     * @param cs
    1104     *            the CharSequence to check, may be null
    1105     * @param searchChars
    1106     *            the chars to search for, may be null
    1107     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
    1108     * @since 2.4
    1109     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
    1110     */
    1111    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
    1112        if (searchChars == null) {
    1113            return false;
    1114        }
    1115        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
    1116    }
    1117
    1118    /**
    1119     * Checks if the CharSequence contains any of the CharSequences in the given array.
    1120     *
    1121     * <p>
    1122     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1123     * return {@code false}.
    1124     * </p>
    1125     *
    1126     * <pre>
    1127     * StringUtils.containsAny(null, *)            = false
    1128     * StringUtils.containsAny("", *)              = false
    1129     * StringUtils.containsAny(*, null)            = false
    1130     * StringUtils.containsAny(*, [])              = false
    1131     * StringUtils.containsAny("abcd", "ab", null) = true
    1132     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1133     * StringUtils.containsAny("abc", "d", "abc")  = true
    1134     * </pre>
    1135     *
    1136     * @param cs The CharSequence to check, may be null
    1137     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1138     *        null as well.
    1139     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1140     * @since 3.4
    1141     */
    1142    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
    1143        return containsAny(StringUtils::contains, cs, searchCharSequences);
    1144    }
    1145
    1146    /**
    1147     * Checks if the CharSequence contains any of the CharSequences in the given array.
    1148     *
    1149     * <p>
    1150     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1151     * return {@code false}.
    1152     * </p>
    1153     *
    1154     * @param cs The CharSequence to check, may be null
    1155     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1156     *        null as well.
    1157     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1158     * @since 3.12.0
    1159     */
    1160    private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
    1161        final CharSequence cs, final CharSequence... searchCharSequences) {
    1162        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
    1163            return false;
    1164        }
    1165        for (final CharSequence searchCharSequence : searchCharSequences) {
    1166            if (test.applyAsBoolean(cs, searchCharSequence)) {
    1167                return true;
    1168            }
    1169        }
    1170        return false;
    1171    }
    1172
    1173    /**
    1174     * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
    1175     *
    1176     * <p>
    1177     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1178     * return {@code false}.
    1179     * </p>
    1180     *
    1181     * <pre>
    1182     * StringUtils.containsAny(null, *)            = false
    1183     * StringUtils.containsAny("", *)              = false
    1184     * StringUtils.containsAny(*, null)            = false
    1185     * StringUtils.containsAny(*, [])              = false
    1186     * StringUtils.containsAny("abcd", "ab", null) = true
    1187     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1188     * StringUtils.containsAny("abc", "d", "abc")  = true
    1189     * StringUtils.containsAny("abc", "D", "ABC")  = true
    1190     * StringUtils.containsAny("ABC", "d", "abc")  = true
    1191     * </pre>
    1192     *
    1193     * @param cs The CharSequence to check, may be null
    1194     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1195     *        null as well.
    1196     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1197     * @since 3.12.0
    1198     */
    1199    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
    1200        return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
    1201    }
    1202
    1203    /**
    1204     * Checks if CharSequence contains a search CharSequence irrespective of case,
    1205     * handling {@code null}. Case-insensitivity is defined as by
    1206     * {@link String#equalsIgnoreCase(String)}.
    1207     *
    1208     * <p>A {@code null} CharSequence will return {@code false}.
    1209     *
    1210     * <pre>
    1211     * StringUtils.containsIgnoreCase(null, *) = false
    1212     * StringUtils.containsIgnoreCase(*, null) = false
    1213     * StringUtils.containsIgnoreCase("", "") = true
    1214     * StringUtils.containsIgnoreCase("abc", "") = true
    1215     * StringUtils.containsIgnoreCase("abc", "a") = true
    1216     * StringUtils.containsIgnoreCase("abc", "z") = false
    1217     * StringUtils.containsIgnoreCase("abc", "A") = true
    1218     * StringUtils.containsIgnoreCase("abc", "Z") = false
    1219     * </pre>
    1220     *
    1221     * @param str  the CharSequence to check, may be null
    1222     * @param searchStr  the CharSequence to find, may be null
    1223     * @return true if the CharSequence contains the search CharSequence irrespective of
    1224     * case or false if not or {@code null} string input
    1225     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
    1226     */
    1227    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1228        if (str == null || searchStr == null) {
    1229            return false;
    1230        }
    1231        final int len = searchStr.length();
    1232        final int max = str.length() - len;
    1233        for (int i = 0; i <= max; i++) {
    1234            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
    1235                return true;
    1236            }
    1237        }
    1238        return false;
    1239    }
    1240
    1241    /**
    1242     * Checks that the CharSequence does not contain certain characters.
    1243     *
    1244     * <p>A {@code null} CharSequence will return {@code true}.
    1245     * A {@code null} invalid character array will return {@code true}.
    1246     * An empty CharSequence (length()=0) always returns true.</p>
    1247     *
    1248     * <pre>
    1249     * StringUtils.containsNone(null, *)       = true
    1250     * StringUtils.containsNone(*, null)       = true
    1251     * StringUtils.containsNone("", *)         = true
    1252     * StringUtils.containsNone("ab", '')      = true
    1253     * StringUtils.containsNone("abab", 'xyz') = true
    1254     * StringUtils.containsNone("ab1", 'xyz')  = true
    1255     * StringUtils.containsNone("abz", 'xyz')  = false
    1256     * </pre>
    1257     *
    1258     * @param cs  the CharSequence to check, may be null
    1259     * @param searchChars  an array of invalid chars, may be null
    1260     * @return true if it contains none of the invalid chars, or is null
    1261     * @since 2.0
    1262     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
    1263     */
    1264    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    1265        if (cs == null || searchChars == null) {
    1266            return true;
    1267        }
    1268        final int csLen = cs.length();
    1269        final int csLast = csLen - 1;
    1270        final int searchLen = searchChars.length;
    1271        final int searchLast = searchLen - 1;
    1272        for (int i = 0; i < csLen; i++) {
    1273            final char ch = cs.charAt(i);
    1274            for (int j = 0; j < searchLen; j++) {
    1275                if (searchChars[j] == ch) {
    1276                    if (!Character.isHighSurrogate(ch)) {
    1277                        // ch is in the Basic Multilingual Plane
    1278                        return false;
    1279                    }
    1280                    if (j == searchLast) {
    1281                        // missing low surrogate, fine, like String.indexOf(String)
    1282                        return false;
    1283                    }
    1284                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1285                        return false;
    1286                    }
    1287                }
    1288            }
    1289        }
    1290        return true;
    1291    }
    1292
    1293    /**
    1294     * Checks that the CharSequence does not contain certain characters.
    1295     *
    1296     * <p>A {@code null} CharSequence will return {@code true}.
    1297     * A {@code null} invalid character array will return {@code true}.
    1298     * An empty String ("") always returns true.</p>
    1299     *
    1300     * <pre>
    1301     * StringUtils.containsNone(null, *)       = true
    1302     * StringUtils.containsNone(*, null)       = true
    1303     * StringUtils.containsNone("", *)         = true
    1304     * StringUtils.containsNone("ab", "")      = true
    1305     * StringUtils.containsNone("abab", "xyz") = true
    1306     * StringUtils.containsNone("ab1", "xyz")  = true
    1307     * StringUtils.containsNone("abz", "xyz")  = false
    1308     * </pre>
    1309     *
    1310     * @param cs  the CharSequence to check, may be null
    1311     * @param invalidChars  a String of invalid chars, may be null
    1312     * @return true if it contains none of the invalid chars, or is null
    1313     * @since 2.0
    1314     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    1315     */
    1316    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
    1317        if (invalidChars == null) {
    1318            return true;
    1319        }
    1320        return containsNone(cs, invalidChars.toCharArray());
    1321    }
    1322
    1323    /**
    1324     * Checks if the CharSequence contains only certain characters.
    1325     *
    1326     * <p>A {@code null} CharSequence will return {@code false}.
    1327     * A {@code null} valid character array will return {@code false}.
    1328     * An empty CharSequence (length()=0) always returns {@code true}.</p>
    1329     *
    1330     * <pre>
    1331     * StringUtils.containsOnly(null, *)       = false
    1332     * StringUtils.containsOnly(*, null)       = false
    1333     * StringUtils.containsOnly("", *)         = true
    1334     * StringUtils.containsOnly("ab", '')      = false
    1335     * StringUtils.containsOnly("abab", 'abc') = true
    1336     * StringUtils.containsOnly("ab1", 'abc')  = false
    1337     * StringUtils.containsOnly("abz", 'abc')  = false
    1338     * </pre>
    1339     *
    1340     * @param cs  the String to check, may be null
    1341     * @param valid  an array of valid chars, may be null
    1342     * @return true if it only contains valid chars and is non-null
    1343     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
    1344     */
    1345    public static boolean containsOnly(final CharSequence cs, final char... valid) {
    1346        // All these pre-checks are to maintain API with an older version
    1347        if (valid == null || cs == null) {
    1348            return false;
    1349        }
    1350        if (cs.length() == 0) {
    1351            return true;
    1352        }
    1353        if (valid.length == 0) {
    1354            return false;
    1355        }
    1356        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    1357    }
    1358
    1359    /**
    1360     * Checks if the CharSequence contains only certain characters.
    1361     *
    1362     * <p>A {@code null} CharSequence will return {@code false}.
    1363     * A {@code null} valid character String will return {@code false}.
    1364     * An empty String (length()=0) always returns {@code true}.</p>
    1365     *
    1366     * <pre>
    1367     * StringUtils.containsOnly(null, *)       = false
    1368     * StringUtils.containsOnly(*, null)       = false
    1369     * StringUtils.containsOnly("", *)         = true
    1370     * StringUtils.containsOnly("ab", "")      = false
    1371     * StringUtils.containsOnly("abab", "abc") = true
    1372     * StringUtils.containsOnly("ab1", "abc")  = false
    1373     * StringUtils.containsOnly("abz", "abc")  = false
    1374     * </pre>
    1375     *
    1376     * @param cs  the CharSequence to check, may be null
    1377     * @param validChars  a String of valid chars, may be null
    1378     * @return true if it only contains valid chars and is non-null
    1379     * @since 2.0
    1380     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    1381     */
    1382    public static boolean containsOnly(final CharSequence cs, final String validChars) {
    1383        if (cs == null || validChars == null) {
    1384            return false;
    1385        }
    1386        return containsOnly(cs, validChars.toCharArray());
    1387    }
    1388
    1389    /**
    1390     * Check whether the given CharSequence contains any whitespace characters.
    1391     *
    1392     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1393     *
    1394     * @param seq the CharSequence to check (may be {@code null})
    1395     * @return {@code true} if the CharSequence is not empty and
    1396     * contains at least 1 (breaking) whitespace character
    1397     * @since 3.0
    1398     */
    1399    // From org.springframework.util.StringUtils, under Apache License 2.0
    1400    public static boolean containsWhitespace(final CharSequence seq) {
    1401        if (isEmpty(seq)) {
    1402            return false;
    1403        }
    1404        final int strLen = seq.length();
    1405        for (int i = 0; i < strLen; i++) {
    1406            if (Character.isWhitespace(seq.charAt(i))) {
    1407                return true;
    1408            }
    1409        }
    1410        return false;
    1411    }
    1412
    1413    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
    1414        for (int i = 0; i < decomposed.length(); i++) {
    1415            if (decomposed.charAt(i) == '\u0141') {
    1416                decomposed.setCharAt(i, 'L');
    1417            } else if (decomposed.charAt(i) == '\u0142') {
    1418                decomposed.setCharAt(i, 'l');
    1419            }
    1420        }
    1421    }
    1422
    1423    /**
    1424     * Counts how many times the char appears in the given string.
    1425     *
    1426     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1427     *
    1428     * <pre>
    1429     * StringUtils.countMatches(null, *)       = 0
    1430     * StringUtils.countMatches("", *)         = 0
    1431     * StringUtils.countMatches("abba", 0)  = 0
    1432     * StringUtils.countMatches("abba", 'a')   = 2
    1433     * StringUtils.countMatches("abba", 'b')  = 2
    1434     * StringUtils.countMatches("abba", 'x') = 0
    1435     * </pre>
    1436     *
    1437     * @param str  the CharSequence to check, may be null
    1438     * @param ch  the char to count
    1439     * @return the number of occurrences, 0 if the CharSequence is {@code null}
    1440     * @since 3.4
    1441     */
    1442    public static int countMatches(final CharSequence str, final char ch) {
    1443        if (isEmpty(str)) {
    1444            return 0;
    1445        }
    1446        int count = 0;
    1447        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
    1448        for (int i = 0; i < str.length(); i++) {
    1449            if (ch == str.charAt(i)) {
    1450                count++;
    1451            }
    1452        }
    1453        return count;
    1454    }
    1455
    1456    /**
    1457     * Counts how many times the substring appears in the larger string.
    1458     * Note that the code only counts non-overlapping matches.
    1459     *
    1460     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1461     *
    1462     * <pre>
    1463     * StringUtils.countMatches(null, *)       = 0
    1464     * StringUtils.countMatches("", *)         = 0
    1465     * StringUtils.countMatches("abba", null)  = 0
    1466     * StringUtils.countMatches("abba", "")    = 0
    1467     * StringUtils.countMatches("abba", "a")   = 2
    1468     * StringUtils.countMatches("abba", "ab")  = 1
    1469     * StringUtils.countMatches("abba", "xxx") = 0
    1470     * StringUtils.countMatches("ababa", "aba") = 1
    1471     * </pre>
    1472     *
    1473     * @param str  the CharSequence to check, may be null
    1474     * @param sub  the substring to count, may be null
    1475     * @return the number of occurrences, 0 if either CharSequence is {@code null}
    1476     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
    1477     */
    1478    public static int countMatches(final CharSequence str, final CharSequence sub) {
    1479        if (isEmpty(str) || isEmpty(sub)) {
    1480            return 0;
    1481        }
    1482        int count = 0;
    1483        int idx = 0;
    1484        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
    1485            count++;
    1486            idx += sub.length();
    1487        }
    1488        return count;
    1489    }
    1490
    1491    /**
    1492     * Returns either the passed in CharSequence, or if the CharSequence is
    1493     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.
    1494     *
    1495     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1496     *
    1497     * <pre>
    1498     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
    1499     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
    1500     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
    1501     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
    1502     * StringUtils.defaultIfBlank("", null)      = null
    1503     * </pre>
    1504     * @param <T> the specific kind of CharSequence
    1505     * @param str the CharSequence to check, may be null
    1506     * @param defaultStr  the default CharSequence to return
    1507     *  if the input is whitespace, empty ("") or {@code null}, may be null
    1508     * @return the passed in CharSequence, or the default
    1509     * @see StringUtils#defaultString(String, String)
    1510     */
    1511    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
    1512        return isBlank(str) ? defaultStr : str;
    1513    }
    1514
    1515    /**
    1516     * Returns either the passed in CharSequence, or if the CharSequence is
    1517     * empty or {@code null}, the value of {@code defaultStr}.
    1518     *
    1519     * <pre>
    1520     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    1521     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    1522     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
    1523     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    1524     * StringUtils.defaultIfEmpty("", null)      = null
    1525     * </pre>
    1526     * @param <T> the specific kind of CharSequence
    1527     * @param str  the CharSequence to check, may be null
    1528     * @param defaultStr  the default CharSequence to return
    1529     *  if the input is empty ("") or {@code null}, may be null
    1530     * @return the passed in CharSequence, or the default
    1531     * @see StringUtils#defaultString(String, String)
    1532     */
    1533    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
    1534        return isEmpty(str) ? defaultStr : str;
    1535    }
    1536
    1537    /**
    1538     * Returns either the passed in String,
    1539     * or if the String is {@code null}, an empty String ("").
    1540     *
    1541     * <pre>
    1542     * StringUtils.defaultString(null)  = ""
    1543     * StringUtils.defaultString("")    = ""
    1544     * StringUtils.defaultString("bat") = "bat"
    1545     * </pre>
    1546     *
    1547     * @see Objects#toString(Object, String)
    1548     * @see String#valueOf(Object)
    1549     * @param str  the String to check, may be null
    1550     * @return the passed in String, or the empty String if it
    1551     *  was {@code null}
    1552     */
    1553    public static String defaultString(final String str) {
    1554        return Objects.toString(str, EMPTY);
    1555    }
    1556
    1557    /**
    1558     * Returns either the given String, or if the String is
    1559     * {@code null}, {@code nullDefault}.
    1560     *
    1561     * <pre>
    1562     * StringUtils.defaultString(null, "NULL")  = "NULL"
    1563     * StringUtils.defaultString("", "NULL")    = ""
    1564     * StringUtils.defaultString("bat", "NULL") = "bat"
    1565     * </pre>
    1566     * <p>
    1567     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
    1568     * </p>
    1569     * <pre>
    1570     * Objects.toString(null, "NULL")  = "NULL"
    1571     * Objects.toString("", "NULL")    = ""
    1572     * Objects.toString("bat", "NULL") = "bat"
    1573     * </pre>
    1574     *
    1575     * @see Objects#toString(Object, String)
    1576     * @see String#valueOf(Object)
    1577     * @param str  the String to check, may be null
    1578     * @param nullDefault  the default String to return
    1579     *  if the input is {@code null}, may be null
    1580     * @return the passed in String, or the default if it was {@code null}
    1581     * @deprecated Use {@link Objects#toString(Object, String)}
    1582     */
    1583    @Deprecated
    1584    public static String defaultString(final String str, final String nullDefault) {
    1585        return Objects.toString(str, nullDefault);
    1586    }
    1587
    1588    /**
    1589     * Deletes all whitespaces from a String as defined by
    1590     * {@link Character#isWhitespace(char)}.
    1591     *
    1592     * <pre>
    1593     * StringUtils.deleteWhitespace(null)         = null
    1594     * StringUtils.deleteWhitespace("")           = ""
    1595     * StringUtils.deleteWhitespace("abc")        = "abc"
    1596     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    1597     * </pre>
    1598     *
    1599     * @param str  the String to delete whitespace from, may be null
    1600     * @return the String without whitespaces, {@code null} if null String input
    1601     */
    1602    public static String deleteWhitespace(final String str) {
    1603        if (isEmpty(str)) {
    1604            return str;
    1605        }
    1606        final int sz = str.length();
    1607        final char[] chs = new char[sz];
    1608        int count = 0;
    1609        for (int i = 0; i < sz; i++) {
    1610            if (!Character.isWhitespace(str.charAt(i))) {
    1611                chs[count++] = str.charAt(i);
    1612            }
    1613        }
    1614        if (count == sz) {
    1615            return str;
    1616        }
    1617        if (count == 0) {
    1618            return EMPTY;
    1619        }
    1620        return new String(chs, 0, count);
    1621    }
    1622
    1623    /**
    1624     * Compares two Strings, and returns the portion where they differ.
    1625     * More precisely, return the remainder of the second String,
    1626     * starting from where it's different from the first. This means that
    1627     * the difference between "abc" and "ab" is the empty String and not "c".
    1628     *
    1629     * <p>For example,
    1630     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
    1631     *
    1632     * <pre>
    1633     * StringUtils.difference(null, null) = null
    1634     * StringUtils.difference("", "") = ""
    1635     * StringUtils.difference("", "abc") = "abc"
    1636     * StringUtils.difference("abc", "") = ""
    1637     * StringUtils.difference("abc", "abc") = ""
    1638     * StringUtils.difference("abc", "ab") = ""
    1639     * StringUtils.difference("ab", "abxyz") = "xyz"
    1640     * StringUtils.difference("abcde", "abxyz") = "xyz"
    1641     * StringUtils.difference("abcde", "xyz") = "xyz"
    1642     * </pre>
    1643     *
    1644     * @param str1  the first String, may be null
    1645     * @param str2  the second String, may be null
    1646     * @return the portion of str2 where it differs from str1; returns the
    1647     * empty String if they are equal
    1648     * @see #indexOfDifference(CharSequence,CharSequence)
    1649     * @since 2.0
    1650     */
    1651    public static String difference(final String str1, final String str2) {
    1652        if (str1 == null) {
    1653            return str2;
    1654        }
    1655        if (str2 == null) {
    1656            return str1;
    1657        }
    1658        final int at = indexOfDifference(str1, str2);
    1659        if (at == INDEX_NOT_FOUND) {
    1660            return EMPTY;
    1661        }
    1662        return str2.substring(at);
    1663    }
    1664
    1665    /**
    1666     * Check if a CharSequence ends with a specified suffix.
    1667     *
    1668     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1669     * references are considered to be equal. The comparison is case-sensitive.</p>
    1670     *
    1671     * <pre>
    1672     * StringUtils.endsWith(null, null)      = true
    1673     * StringUtils.endsWith(null, "def")     = false
    1674     * StringUtils.endsWith("abcdef", null)  = false
    1675     * StringUtils.endsWith("abcdef", "def") = true
    1676     * StringUtils.endsWith("ABCDEF", "def") = false
    1677     * StringUtils.endsWith("ABCDEF", "cde") = false
    1678     * StringUtils.endsWith("ABCDEF", "")    = true
    1679     * </pre>
    1680     *
    1681     * @see String#endsWith(String)
    1682     * @param str  the CharSequence to check, may be null
    1683     * @param suffix the suffix to find, may be null
    1684     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
    1685     *  both {@code null}
    1686     * @since 2.4
    1687     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
    1688     */
    1689    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
    1690        return endsWith(str, suffix, false);
    1691    }
    1692
    1693    /**
    1694     * Check if a CharSequence ends with a specified suffix (optionally case insensitive).
    1695     *
    1696     * @see String#endsWith(String)
    1697     * @param str  the CharSequence to check, may be null
    1698     * @param suffix the suffix to find, may be null
    1699     * @param ignoreCase indicates whether the compare should ignore case
    1700     *  (case-insensitive) or not.
    1701     * @return {@code true} if the CharSequence starts with the prefix or
    1702     *  both {@code null}
    1703     */
    1704    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
    1705        if (str == null || suffix == null) {
    1706            return str == suffix;
    1707        }
    1708        if (suffix.length() > str.length()) {
    1709            return false;
    1710        }
    1711        final int strOffset = str.length() - suffix.length();
    1712        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
    1713    }
    1714
    1715    /**
    1716     * Check if a CharSequence ends with any of the provided case-sensitive suffixes.
    1717     *
    1718     * <pre>
    1719     * StringUtils.endsWithAny(null, null)      = false
    1720     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
    1721     * StringUtils.endsWithAny("abcxyz", null)     = false
    1722     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
    1723     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
    1724     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    1725     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
    1726     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
    1727     * </pre>
    1728     *
    1729     * @param sequence  the CharSequence to check, may be null
    1730     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
    1731     * @see StringUtils#endsWith(CharSequence, CharSequence)
    1732     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    1733     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
    1734     * @since 3.0
    1735     */
    1736    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    1737        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    1738            return false;
    1739        }
    1740        for (final CharSequence searchString : searchStrings) {
    1741            if (endsWith(sequence, searchString)) {
    1742                return true;
    1743            }
    1744        }
    1745        return false;
    1746    }
    1747
    1748    /**
    1749     * Case insensitive check if a CharSequence ends with a specified suffix.
    1750     *
    1751     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1752     * references are considered to be equal. The comparison is case insensitive.</p>
    1753     *
    1754     * <pre>
    1755     * StringUtils.endsWithIgnoreCase(null, null)      = true
    1756     * StringUtils.endsWithIgnoreCase(null, "def")     = false
    1757     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    1758     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    1759     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    1760     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    1761     * </pre>
    1762     *
    1763     * @see String#endsWith(String)
    1764     * @param str  the CharSequence to check, may be null
    1765     * @param suffix the suffix to find, may be null
    1766     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
    1767     *  both {@code null}
    1768     * @since 2.4
    1769     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
    1770     */
    1771    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
    1772        return endsWith(str, suffix, true);
    1773    }
    1774
    1775    /**
    1776     * Compares two CharSequences, returning {@code true} if they represent
    1777     * equal sequences of characters.
    1778     *
    1779     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1780     * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
    1781     *
    1782     * <pre>
    1783     * StringUtils.equals(null, null)   = true
    1784     * StringUtils.equals(null, "abc")  = false
    1785     * StringUtils.equals("abc", null)  = false
    1786     * StringUtils.equals("abc", "abc") = true
    1787     * StringUtils.equals("abc", "ABC") = false
    1788     * </pre>
    1789     *
    1790     * @param cs1  the first CharSequence, may be {@code null}
    1791     * @param cs2  the second CharSequence, may be {@code null}
    1792     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
    1793     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    1794     * @see Object#equals(Object)
    1795     * @see #equalsIgnoreCase(CharSequence, CharSequence)
    1796     */
    1797    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
    1798        if (cs1 == cs2) {
    1799            return true;
    1800        }
    1801        if (cs1 == null || cs2 == null) {
    1802            return false;
    1803        }
    1804        if (cs1.length() != cs2.length()) {
    1805            return false;
    1806        }
    1807        if (cs1 instanceof String && cs2 instanceof String) {
    1808            return cs1.equals(cs2);
    1809        }
    1810        // Step-wise comparison
    1811        final int length = cs1.length();
    1812        for (int i = 0; i < length; i++) {
    1813            if (cs1.charAt(i) != cs2.charAt(i)) {
    1814                return false;
    1815            }
    1816        }
    1817        return true;
    1818    }
    1819
    1820    /**
    1821     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1822     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
    1823     *
    1824     * <pre>
    1825     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
    1826     * StringUtils.equalsAny(null, null, null)    = true
    1827     * StringUtils.equalsAny(null, "abc", "def")  = false
    1828     * StringUtils.equalsAny("abc", null, "def")  = false
    1829     * StringUtils.equalsAny("abc", "abc", "def") = true
    1830     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
    1831     * </pre>
    1832     *
    1833     * @param string to compare, may be {@code null}.
    1834     * @param searchStrings a vararg of strings, may be {@code null}.
    1835     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
    1836     * {@code false} if {@code searchStrings} is null or contains no matches.
    1837     * @since 3.5
    1838     */
    1839    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
    1840        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1841            for (final CharSequence next : searchStrings) {
    1842                if (equals(string, next)) {
    1843                    return true;
    1844                }
    1845            }
    1846        }
    1847        return false;
    1848    }
    1849
    1850    /**
    1851     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1852     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
    1853     *
    1854     * <pre>
    1855     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
    1856     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
    1857     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
    1858     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
    1859     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
    1860     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
    1861     * </pre>
    1862     *
    1863     * @param string to compare, may be {@code null}.
    1864     * @param searchStrings a vararg of strings, may be {@code null}.
    1865     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
    1866     * {@code false} if {@code searchStrings} is null or contains no matches.
    1867     * @since 3.5
    1868     */
    1869    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
    1870        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1871            for (final CharSequence next : searchStrings) {
    1872                if (equalsIgnoreCase(string, next)) {
    1873                    return true;
    1874                }
    1875            }
    1876        }
    1877        return false;
    1878    }
    1879
    1880    /**
    1881     * Compares two CharSequences, returning {@code true} if they represent
    1882     * equal sequences of characters, ignoring case.
    1883     *
    1884     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1885     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
    1886     *
    1887     * <pre>
    1888     * StringUtils.equalsIgnoreCase(null, null)   = true
    1889     * StringUtils.equalsIgnoreCase(null, "abc")  = false
    1890     * StringUtils.equalsIgnoreCase("abc", null)  = false
    1891     * StringUtils.equalsIgnoreCase("abc", "abc") = true
    1892     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    1893     * </pre>
    1894     *
    1895     * @param cs1  the first CharSequence, may be {@code null}
    1896     * @param cs2  the second CharSequence, may be {@code null}
    1897     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
    1898     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
    1899     * @see #equals(CharSequence, CharSequence)
    1900     */
    1901    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
    1902        if (cs1 == cs2) {
    1903            return true;
    1904        }
    1905        if (cs1 == null || cs2 == null) {
    1906            return false;
    1907        }
    1908        if (cs1.length() != cs2.length()) {
    1909            return false;
    1910        }
    1911        return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
    1912    }
    1913
    1914    /**
    1915     * Returns the first value in the array which is not empty (""),
    1916     * {@code null} or whitespace only.
    1917     *
    1918     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1919     *
    1920     * <p>If all values are blank or the array is {@code null}
    1921     * or empty then {@code null} is returned.</p>
    1922     *
    1923     * <pre>
    1924     * StringUtils.firstNonBlank(null, null, null)     = null
    1925     * StringUtils.firstNonBlank(null, "", " ")        = null
    1926     * StringUtils.firstNonBlank("abc")                = "abc"
    1927     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
    1928     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
    1929     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
    1930     * StringUtils.firstNonBlank()                     = null
    1931     * </pre>
    1932     *
    1933     * @param <T> the specific kind of CharSequence
    1934     * @param values  the values to test, may be {@code null} or empty
    1935     * @return the first value from {@code values} which is not blank,
    1936     *  or {@code null} if there are no non-blank values
    1937     * @since 3.8
    1938     */
    1939    @SafeVarargs
    1940    public static <T extends CharSequence> T firstNonBlank(final T... values) {
    1941        if (values != null) {
    1942            for (final T val : values) {
    1943                if (isNotBlank(val)) {
    1944                    return val;
    1945                }
    1946            }
    1947        }
    1948        return null;
    1949    }
    1950
    1951    /**
    1952     * Returns the first value in the array which is not empty.
    1953     *
    1954     * <p>If all values are empty or the array is {@code null}
    1955     * or empty then {@code null} is returned.</p>
    1956     *
    1957     * <pre>
    1958     * StringUtils.firstNonEmpty(null, null, null)   = null
    1959     * StringUtils.firstNonEmpty(null, null, "")     = null
    1960     * StringUtils.firstNonEmpty(null, "", " ")      = " "
    1961     * StringUtils.firstNonEmpty("abc")              = "abc"
    1962     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
    1963     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
    1964     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
    1965     * StringUtils.firstNonEmpty()                   = null
    1966     * </pre>
    1967     *
    1968     * @param <T> the specific kind of CharSequence
    1969     * @param values  the values to test, may be {@code null} or empty
    1970     * @return the first value from {@code values} which is not empty,
    1971     *  or {@code null} if there are no non-empty values
    1972     * @since 3.8
    1973     */
    1974    @SafeVarargs
    1975    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
    1976        if (values != null) {
    1977            for (final T val : values) {
    1978                if (isNotEmpty(val)) {
    1979                    return val;
    1980                }
    1981            }
    1982        }
    1983        return null;
    1984    }
    1985
    1986    /**
    1987     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
    1988     *
    1989     * @param string input string
    1990     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
    1991     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
    1992     * @see String#getBytes(Charset)
    1993     * @since 3.10
    1994     */
    1995    public static byte[] getBytes(final String string, final Charset charset) {
    1996        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
    1997    }
    1998
    1999    /**
    2000     * Calls {@link String#getBytes(String)} in a null-safe manner.
    2001     *
    2002     * @param string input string
    2003     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
    2004     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
    2005     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
    2006     * @see String#getBytes(String)
    2007     * @since 3.10
    2008     */
    2009    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
    2010        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
    2011    }
    2012
    2013    /**
    2014     * Compares all Strings in an array and returns the initial sequence of
    2015     * characters that is common to all of them.
    2016     *
    2017     * <p>For example,
    2018     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
    2019     *
    2020     * <pre>
    2021     * StringUtils.getCommonPrefix(null) = ""
    2022     * StringUtils.getCommonPrefix(new String[] {}) = ""
    2023     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
    2024     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
    2025     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
    2026     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
    2027     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    2028     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    2029     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
    2030     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
    2031     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
    2032     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
    2033     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
    2034     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
    2035     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
    2036     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
    2037     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    2038     * </pre>
    2039     *
    2040     * @param strs  array of String objects, entries may be null
    2041     * @return the initial sequence of characters that are common to all Strings
    2042     * in the array; empty String if the array is null, the elements are all null
    2043     * or if there is no common prefix.
    2044     * @since 2.4
    2045     */
    2046    public static String getCommonPrefix(final String... strs) {
    2047        if (ArrayUtils.isEmpty(strs)) {
    2048            return EMPTY;
    2049        }
    2050        final int smallestIndexOfDiff = indexOfDifference(strs);
    2051        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    2052            // all strings were identical
    2053            if (strs[0] == null) {
    2054                return EMPTY;
    2055            }
    2056            return strs[0];
    2057        }
    2058        if (smallestIndexOfDiff == 0) {
    2059            // there were no common initial characters
    2060            return EMPTY;
    2061        }
    2062        // we found a common initial character sequence
    2063        return strs[0].substring(0, smallestIndexOfDiff);
    2064    }
    2065
    2066    /**
    2067     * Checks if a String {@code str} contains Unicode digits,
    2068     * if yes then concatenate all the digits in {@code str} and return it as a String.
    2069     *
    2070     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
    2071     *
    2072     * <pre>
    2073     * StringUtils.getDigits(null)  = null
    2074     * StringUtils.getDigits("")    = ""
    2075     * StringUtils.getDigits("abc") = ""
    2076     * StringUtils.getDigits("1000$") = "1000"
    2077     * StringUtils.getDigits("1123~45") = "112345"
    2078     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
    2079     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
    2080     * </pre>
    2081     *
    2082     * @param str the String to extract digits from, may be null
    2083     * @return String with only digits,
    2084     *           or an empty ("") String if no digits found,
    2085     *           or {@code null} String if {@code str} is null
    2086     * @since 3.6
    2087     */
    2088    public static String getDigits(final String str) {
    2089        if (isEmpty(str)) {
    2090            return str;
    2091        }
    2092        final int sz = str.length();
    2093        final StringBuilder strDigits = new StringBuilder(sz);
    2094        for (int i = 0; i < sz; i++) {
    2095            final char tempChar = str.charAt(i);
    2096            if (Character.isDigit(tempChar)) {
    2097                strDigits.append(tempChar);
    2098            }
    2099        }
    2100        return strDigits.toString();
    2101    }
    2102
    2103    /**
    2104     * Find the Fuzzy Distance which indicates the similarity score between two Strings.
    2105     *
    2106     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
    2107     * TextMate, Atom and others. One point is given for every matched character. Subsequent
    2108     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
    2109     *
    2110     * <pre>
    2111     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
    2112     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
    2113     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
    2114     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
    2115     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
    2116     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
    2117     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
    2118     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
    2119     * </pre>
    2120     *
    2121     * @param term a full term that should be matched against, must not be null
    2122     * @param query the query that will be matched against a term, must not be null
    2123     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
    2124     *  both Strings to lower case.
    2125     * @return result score
    2126     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
    2127     * @since 3.4
    2128     * @deprecated As of 3.6, use Apache Commons Text
    2129     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
    2130     * FuzzyScore</a> instead
    2131     */
    2132    @Deprecated
    2133    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
    2134        if (term == null || query == null) {
    2135            throw new IllegalArgumentException("Strings must not be null");
    2136        }
    2137        if (locale == null) {
    2138            throw new IllegalArgumentException("Locale must not be null");
    2139        }
    2140
    2141        // fuzzy logic is case-insensitive. We normalize the Strings to lower
    2142        // case right from the start. Turning characters to lower case
    2143        // via Character.toLowerCase(char) is unfortunately insufficient
    2144        // as it does not accept a locale.
    2145        final String termLowerCase = term.toString().toLowerCase(locale);
    2146        final String queryLowerCase = query.toString().toLowerCase(locale);
    2147
    2148        // the resulting score
    2149        int score = 0;
    2150
    2151        // the position in the term which will be scanned next for potential
    2152        // query character matches
    2153        int termIndex = 0;
    2154
    2155        // index of the previously matched character in the term
    2156        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
    2157
    2158        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
    2159            final char queryChar = queryLowerCase.charAt(queryIndex);
    2160
    2161            boolean termCharacterMatchFound = false;
    2162            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
    2163                final char termChar = termLowerCase.charAt(termIndex);
    2164
    2165                if (queryChar == termChar) {
    2166                    // simple character matches result in one point
    2167                    score++;
    2168
    2169                    // subsequent character matches further improve
    2170                    // the score.
    2171                    if (previousMatchingCharacterIndex + 1 == termIndex) {
    2172                        score += 2;
    2173                    }
    2174
    2175                    previousMatchingCharacterIndex = termIndex;
    2176
    2177                    // we can leave the nested loop. Every character in the
    2178                    // query can match at most one character in the term.
    2179                    termCharacterMatchFound = true;
    2180                }
    2181            }
    2182        }
    2183
    2184        return score;
    2185    }
    2186
    2187    /**
    2188     * Returns either the passed in CharSequence, or if the CharSequence is
    2189     * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.
    2190     *
    2191     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    2192     *
    2193     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2194     *
    2195     * <pre>
    2196     * {@code
    2197     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
    2198     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
    2199     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
    2200     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
    2201     * StringUtils.getIfBlank("", () -> null)       = null
    2202     * StringUtils.getIfBlank("", null)             = null
    2203     * }</pre>
    2204     * @param <T> the specific kind of CharSequence
    2205     * @param str the CharSequence to check, may be null
    2206     * @param defaultSupplier the supplier of default CharSequence to return
    2207     *  if the input is whitespace, empty ("") or {@code null}, may be null
    2208     * @return the passed in CharSequence, or the default
    2209     * @see StringUtils#defaultString(String, String)
    2210     * @since 3.10
    2211     */
    2212    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
    2213        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
    2214    }
    2215
    2216    /**
    2217     * Returns either the passed in CharSequence, or if the CharSequence is
    2218     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
    2219     *
    2220     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2221     *
    2222     * <pre>
    2223     * {@code
    2224     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
    2225     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
    2226     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
    2227     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
    2228     * StringUtils.getIfEmpty("", () -> null)        = null
    2229     * StringUtils.getIfEmpty("", null)              = null
    2230     * }
    2231     * </pre>
    2232     * @param <T> the specific kind of CharSequence
    2233     * @param str  the CharSequence to check, may be null
    2234     * @param defaultSupplier  the supplier of default CharSequence to return
    2235     *  if the input is empty ("") or {@code null}, may be null
    2236     * @return the passed in CharSequence, or the default
    2237     * @see StringUtils#defaultString(String, String)
    2238     * @since 3.10
    2239     */
    2240    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
    2241        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
    2242    }
    2243
    2244    /**
    2245     * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
    2246     *
    2247     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
    2248     * Winkler increased this measure for matching initial characters.</p>
    2249     *
    2250     * <p>This implementation is based on the Jaro Winkler similarity algorithm
    2251     * 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>
    2252     *
    2253     * <pre>
    2254     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
    2255     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
    2256     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
    2257     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
    2258     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
    2259     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
    2260     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
    2261     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
    2262     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
    2263     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
    2264     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
    2265     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
    2266     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
    2267     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
    2268     * </pre>
    2269     *
    2270     * @param first the first String, must not be null
    2271     * @param second the second String, must not be null
    2272     * @return result distance
    2273     * @throws IllegalArgumentException if either String input {@code null}
    2274     * @since 3.3
    2275     * @deprecated As of 3.6, use Apache Commons Text
    2276     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
    2277     * JaroWinklerDistance</a> instead
    2278     */
    2279    @Deprecated
    2280    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
    2281        final double DEFAULT_SCALING_FACTOR = 0.1;
    2282
    2283        if (first == null || second == null) {
    2284            throw new IllegalArgumentException("Strings must not be null");
    2285        }
    2286
    2287        final int[] mtp = matches(first, second);
    2288        final double m = mtp[0];
    2289        if (m == 0) {
    2290            return 0D;
    2291        }
    2292        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
    2293        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
    2294        return Math.round(jw * 100.0D) / 100.0D;
    2295    }
    2296
    2297    /**
    2298     * Find the Levenshtein distance between two Strings.
    2299     *
    2300     * <p>This is the number of changes needed to change one String into
    2301     * another, where each change is a single character modification (deletion,
    2302     * insertion or substitution).</p>
    2303     *
    2304     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
    2305     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
    2306     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
    2307     *
    2308     * <pre>
    2309     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    2310     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    2311     * StringUtils.getLevenshteinDistance("", "")              = 0
    2312     * StringUtils.getLevenshteinDistance("", "a")             = 1
    2313     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    2314     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    2315     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    2316     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    2317     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    2318     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    2319     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    2320     * </pre>
    2321     *
    2322     * @param s  the first String, must not be null
    2323     * @param t  the second String, must not be null
    2324     * @return result distance
    2325     * @throws IllegalArgumentException if either String input {@code null}
    2326     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
    2327     * getLevenshteinDistance(CharSequence, CharSequence)
    2328     * @deprecated As of 3.6, use Apache Commons Text
    2329     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2330     * LevenshteinDistance</a> instead
    2331     */
    2332    @Deprecated
    2333    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    2334        if (s == null || t == null) {
    2335            throw new IllegalArgumentException("Strings must not be null");
    2336        }
    2337
    2338        int n = s.length();
    2339        int m = t.length();
    2340
    2341        if (n == 0) {
    2342            return m;
    2343        }
    2344        if (m == 0) {
    2345            return n;
    2346        }
    2347
    2348        if (n > m) {
    2349            // swap the input strings to consume less memory
    2350            final CharSequence tmp = s;
    2351            s = t;
    2352            t = tmp;
    2353            n = m;
    2354            m = t.length();
    2355        }
    2356
    2357        final int[] p = new int[n + 1];
    2358        // indexes into strings s and t
    2359        int i; // iterates through s
    2360        int j; // iterates through t
    2361        int upperleft;
    2362        int upper;
    2363
    2364        char jOfT; // jth character of t
    2365        int cost;
    2366
    2367        for (i = 0; i <= n; i++) {
    2368            p[i] = i;
    2369        }
    2370
    2371        for (j = 1; j <= m; j++) {
    2372            upperleft = p[0];
    2373            jOfT = t.charAt(j - 1);
    2374            p[0] = j;
    2375
    2376            for (i = 1; i <= n; i++) {
    2377                upper = p[i];
    2378                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
    2379                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    2380                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
    2381                upperleft = upper;
    2382            }
    2383        }
    2384
    2385        return p[n];
    2386    }
    2387
    2388    /**
    2389     * Find the Levenshtein distance between two Strings if it's less than or equal to a given
    2390     * threshold.
    2391     *
    2392     * <p>This is the number of changes needed to change one String into
    2393     * another, where each change is a single character modification (deletion,
    2394     * insertion or substitution).</p>
    2395     *
    2396     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
    2397     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
    2398     * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
    2399     *
    2400     * <pre>
    2401     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
    2402     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
    2403     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
    2404     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
    2405     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
    2406     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
    2407     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
    2408     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
    2409     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
    2410     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
    2411     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
    2412     * </pre>
    2413     *
    2414     * @param s  the first String, must not be null
    2415     * @param t  the second String, must not be null
    2416     * @param threshold the target threshold, must not be negative
    2417     * @return result distance, or {@code -1} if the distance would be greater than the threshold
    2418     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
    2419     * @deprecated As of 3.6, use Apache Commons Text
    2420     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2421     * LevenshteinDistance</a> instead
    2422     */
    2423    @Deprecated
    2424    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
    2425        if (s == null || t == null) {
    2426            throw new IllegalArgumentException("Strings must not be null");
    2427        }
    2428        if (threshold < 0) {
    2429            throw new IllegalArgumentException("Threshold must not be negative");
    2430        }
    2431
    2432        /*
    2433        This implementation only computes the distance if it's less than or equal to the
    2434        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    2435        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    2436        computing a diagonal stripe of width 2k + 1 of the cost table.
    2437        It is also possible to use this to compute the unbounded Levenshtein distance by starting
    2438        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    2439        d is the distance.
    2440
    2441        One subtlety comes from needing to ignore entries on the border of our stripe
    2442        eg.
    2443        p[] = |#|#|#|*
    2444        d[] =  *|#|#|#|
    2445        We must ignore the entry to the left of the leftmost member
    2446        We must ignore the entry above the rightmost member
    2447
    2448        Another subtlety comes from our stripe running off the matrix if the strings aren't
    2449        of the same size.  Since string s is always swapped to be the shorter of the two,
    2450        the stripe will always run off to the upper right instead of the lower left of the matrix.
    2451
    2452        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    2453        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
    2454
    2455           1 2 3 4 5
    2456        1 |#|#| | | |
    2457        2 |#|#|#| | |
    2458        3 | |#|#|#| |
    2459        4 | | |#|#|#|
    2460        5 | | | |#|#|
    2461        6 | | | | |#|
    2462        7 | | | | | |
    2463
    2464        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    2465        into one of length 7 in edit distance of 1.
    2466
    2467        Additionally, this implementation decreases memory usage by using two
    2468        single-dimensional arrays and swapping them back and forth instead of allocating
    2469        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    2470        when it's detected that the stripe has run off the matrix and initially filling the arrays with
    2471        large values so that entries we don't compute are ignored.
    2472
    2473        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
    2474         */
    2475
    2476        int n = s.length(); // length of s
    2477        int m = t.length(); // length of t
    2478
    2479        // if one string is empty, the edit distance is necessarily the length of the other
    2480        if (n == 0) {
    2481            return m <= threshold ? m : -1;
    2482        }
    2483        if (m == 0) {
    2484            return n <= threshold ? n : -1;
    2485        }
    2486        if (Math.abs(n - m) > threshold) {
    2487            // no need to calculate the distance if the length difference is greater than the threshold
    2488            return -1;
    2489        }
    2490
    2491        if (n > m) {
    2492            // swap the two strings to consume less memory
    2493            final CharSequence tmp = s;
    2494            s = t;
    2495            t = tmp;
    2496            n = m;
    2497            m = t.length();
    2498        }
    2499
    2500        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
    2501        int[] d = new int[n + 1]; // cost array, horizontally
    2502        int[] tmp; // placeholder to assist in swapping p and d
    2503
    2504        // fill in starting table values
    2505        final int boundary = Math.min(n, threshold) + 1;
    2506        for (int i = 0; i < boundary; i++) {
    2507            p[i] = i;
    2508        }
    2509        // these fills ensure that the value above the rightmost entry of our
    2510        // stripe will be ignored in following loop iterations
    2511        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    2512        Arrays.fill(d, Integer.MAX_VALUE);
    2513
    2514        // iterates through t
    2515        for (int j = 1; j <= m; j++) {
    2516            final char jOfT = t.charAt(j - 1); // jth character of t
    2517            d[0] = j;
    2518
    2519            // compute stripe indices, constrain to array size
    2520            final int min = Math.max(1, j - threshold);
    2521            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
    2522
    2523            // the stripe may lead off of the table if s and t are of different sizes
    2524            if (min > max) {
    2525                return -1;
    2526            }
    2527
    2528            // ignore entry left of leftmost
    2529            if (min > 1) {
    2530                d[min - 1] = Integer.MAX_VALUE;
    2531            }
    2532
    2533            // iterates through [min, max] in s
    2534            for (int i = min; i <= max; i++) {
    2535                if (s.charAt(i - 1) == jOfT) {
    2536                    // diagonally left and up
    2537                    d[i] = p[i - 1];
    2538                } else {
    2539                    // 1 + minimum of cell to the left, to the top, diagonally left and up
    2540                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
    2541                }
    2542            }
    2543
    2544            // copy current distance counts to 'previous row' distance counts
    2545            tmp = p;
    2546            p = d;
    2547            d = tmp;
    2548        }
    2549
    2550        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    2551        // distance
    2552        if (p[n] <= threshold) {
    2553            return p[n];
    2554        }
    2555        return -1;
    2556    }
    2557
    2558    /**
    2559     * Finds the first index within a CharSequence, handling {@code null}.
    2560     * This method uses {@link String#indexOf(String, int)} if possible.
    2561     *
    2562     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    2563     *
    2564     * <pre>
    2565     * StringUtils.indexOf(null, *)          = -1
    2566     * StringUtils.indexOf(*, null)          = -1
    2567     * StringUtils.indexOf("", "")           = 0
    2568     * StringUtils.indexOf("", *)            = -1 (except when * = "")
    2569     * StringUtils.indexOf("aabaabaa", "a")  = 0
    2570     * StringUtils.indexOf("aabaabaa", "b")  = 2
    2571     * StringUtils.indexOf("aabaabaa", "ab") = 1
    2572     * StringUtils.indexOf("aabaabaa", "")   = 0
    2573     * </pre>
    2574     *
    2575     * @param seq  the CharSequence to check, may be null
    2576     * @param searchSeq  the CharSequence to find, may be null
    2577     * @return the first index of the search CharSequence,
    2578     *  -1 if no match or {@code null} string input
    2579     * @since 2.0
    2580     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
    2581     */
    2582    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
    2583        if (seq == null || searchSeq == null) {
    2584            return INDEX_NOT_FOUND;
    2585        }
    2586        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
    2587    }
    2588
    2589    /**
    2590     * Finds the first index within a CharSequence, handling {@code null}.
    2591     * This method uses {@link String#indexOf(String, int)} if possible.
    2592     *
    2593     * <p>A {@code null} CharSequence will return {@code -1}.
    2594     * A negative start position is treated as zero.
    2595     * An empty ("") search CharSequence always matches.
    2596     * A start position greater than the string length only matches
    2597     * an empty search CharSequence.</p>
    2598     *
    2599     * <pre>
    2600     * StringUtils.indexOf(null, *, *)          = -1
    2601     * StringUtils.indexOf(*, null, *)          = -1
    2602     * StringUtils.indexOf("", "", 0)           = 0
    2603     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    2604     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    2605     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    2606     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    2607     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    2608     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    2609     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    2610     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    2611     * StringUtils.indexOf("abc", "", 9)        = 3
    2612     * </pre>
    2613     *
    2614     * @param seq  the CharSequence to check, may be null
    2615     * @param searchSeq  the CharSequence to find, may be null
    2616     * @param startPos  the start position, negative treated as zero
    2617     * @return the first index of the search CharSequence (always &ge; startPos),
    2618     *  -1 if no match or {@code null} string input
    2619     * @since 2.0
    2620     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
    2621     */
    2622    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    2623        if (seq == null || searchSeq == null) {
    2624            return INDEX_NOT_FOUND;
    2625        }
    2626        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
    2627    }
    2628
    2629    /**
    2630     * Returns the index within {@code seq} of the first occurrence of
    2631     * the specified character. If a character with value
    2632     * {@code searchChar} occurs in the character sequence represented by
    2633     * {@code seq} {@link CharSequence} object, then the index (in Unicode
    2634     * code units) of the first such occurrence is returned. For
    2635     * values of {@code searchChar} in the range from 0 to 0xFFFF
    2636     * (inclusive), this is the smallest value <i>k</i> such that:
    2637     * <blockquote><pre>
    2638     * this.charAt(<i>k</i>) == searchChar
    2639     * </pre></blockquote>
    2640     * is true. For other values of {@code searchChar}, it is the
    2641     * smallest value <i>k</i> such that:
    2642     * <blockquote><pre>
    2643     * this.codePointAt(<i>k</i>) == searchChar
    2644     * </pre></blockquote>
    2645     * is true. In either case, if no such character occurs in {@code seq},
    2646     * then {@code INDEX_NOT_FOUND (-1)} is returned.
    2647     *
    2648     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
    2649     * return {@code INDEX_NOT_FOUND (-1)}.</p>
    2650     *
    2651     * <pre>
    2652     * StringUtils.indexOf(null, *)         = -1
    2653     * StringUtils.indexOf("", *)           = -1
    2654     * StringUtils.indexOf("aabaabaa", 'a') = 0
    2655     * StringUtils.indexOf("aabaabaa", 'b') = 2
    2656     * </pre>
    2657     *
    2658     * @param seq  the CharSequence to check, may be null
    2659     * @param searchChar  the character to find
    2660     * @return the first index of the search character,
    2661     *  -1 if no match or {@code null} string input
    2662     * @since 2.0
    2663     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
    2664     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2665     */
    2666    public static int indexOf(final CharSequence seq, final int searchChar) {
    2667        if (isEmpty(seq)) {
    2668            return INDEX_NOT_FOUND;
    2669        }
    2670        return CharSequenceUtils.indexOf(seq, searchChar, 0);
    2671    }
    2672
    2673    /**
    2674     * Returns the index within {@code seq} of the first occurrence of the
    2675     * specified character, starting the search at the specified index.
    2676     * <p>
    2677     * If a character with value {@code searchChar} occurs in the
    2678     * character sequence represented by the {@code seq} {@link CharSequence}
    2679     * object at an index no smaller than {@code startPos}, then
    2680     * the index of the first such occurrence is returned. For values
    2681     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
    2682     * this is the smallest value <i>k</i> such that:
    2683     * <blockquote><pre>
    2684     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    2685     * </pre></blockquote>
    2686     * is true. For other values of {@code searchChar}, it is the
    2687     * smallest value <i>k</i> such that:
    2688     * <blockquote><pre>
    2689     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    2690     * </pre></blockquote>
    2691     * is true. In either case, if no such character occurs in {@code seq}
    2692     * at or after position {@code startPos}, then
    2693     * {@code -1} is returned.
    2694     *
    2695     * <p>
    2696     * There is no restriction on the value of {@code startPos}. If it
    2697     * is negative, it has the same effect as if it were zero: this entire
    2698     * string may be searched. If it is greater than the length of this
    2699     * string, it has the same effect as if it were equal to the length of
    2700     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
    2701     * {@code null} or empty ("") CharSequence will
    2702     * return {@code (INDEX_NOT_FOUND) -1}.
    2703     *
    2704     * <p>All indices are specified in {@code char} values
    2705     * (Unicode code units).
    2706     *
    2707     * <pre>
    2708     * StringUtils.indexOf(null, *, *)          = -1
    2709     * StringUtils.indexOf("", *, *)            = -1
    2710     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    2711     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    2712     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    2713     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    2714     * </pre>
    2715     *
    2716     * @param seq  the CharSequence to check, may be null
    2717     * @param searchChar  the character to find
    2718     * @param startPos  the start position, negative treated as zero
    2719     * @return the first index of the search character (always &ge; startPos),
    2720     *  -1 if no match or {@code null} string input
    2721     * @since 2.0
    2722     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
    2723     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2724     */
    2725    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
    2726        if (isEmpty(seq)) {
    2727            return INDEX_NOT_FOUND;
    2728        }
    2729        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
    2730    }
    2731
    2732    /**
    2733     * Search a CharSequence to find the first index of any
    2734     * character in the given set of characters.
    2735     *
    2736     * <p>A {@code null} String will return {@code -1}.
    2737     * A {@code null} or zero length search array will return {@code -1}.</p>
    2738     *
    2739     * <pre>
    2740     * StringUtils.indexOfAny(null, *)                  = -1
    2741     * StringUtils.indexOfAny("", *)                    = -1
    2742     * StringUtils.indexOfAny(*, null)                  = -1
    2743     * StringUtils.indexOfAny(*, [])                    = -1
    2744     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
    2745     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
    2746     * StringUtils.indexOfAny("aba", ['z'])             = -1
    2747     * </pre>
    2748     *
    2749     * @param cs  the CharSequence to check, may be null
    2750     * @param searchChars  the chars to search for, may be null
    2751     * @return the index of any of the chars, -1 if no match or null input
    2752     * @since 2.0
    2753     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2754     */
    2755    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    2756        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2757            return INDEX_NOT_FOUND;
    2758        }
    2759        final int csLen = cs.length();
    2760        final int csLast = csLen - 1;
    2761        final int searchLen = searchChars.length;
    2762        final int searchLast = searchLen - 1;
    2763        for (int i = 0; i < csLen; i++) {
    2764            final char ch = cs.charAt(i);
    2765            for (int j = 0; j < searchLen; j++) {
    2766                if (searchChars[j] == ch) {
    2767                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
    2768                        return i;
    2769                    }
    2770                    // ch is a supplementary character
    2771                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2772                        return i;
    2773                    }
    2774                }
    2775            }
    2776        }
    2777        return INDEX_NOT_FOUND;
    2778    }
    2779
    2780    /**
    2781     * Find the first index of any of a set of potential substrings.
    2782     *
    2783     * <p>A {@code null} CharSequence will return {@code -1}.
    2784     * A {@code null} or zero length search array will return {@code -1}.
    2785     * A {@code null} search array entry will be ignored, but a search
    2786     * array containing "" will return {@code 0} if {@code str} is not
    2787     * null. This method uses {@link String#indexOf(String)} if possible.</p>
    2788     *
    2789     * <pre>
    2790     * StringUtils.indexOfAny(null, *)                      = -1
    2791     * StringUtils.indexOfAny(*, null)                      = -1
    2792     * StringUtils.indexOfAny(*, [])                        = -1
    2793     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
    2794     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
    2795     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
    2796     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
    2797     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
    2798     * StringUtils.indexOfAny("", [""])                     = 0
    2799     * StringUtils.indexOfAny("", ["a"])                    = -1
    2800     * </pre>
    2801     *
    2802     * @param str  the CharSequence to check, may be null
    2803     * @param searchStrs  the CharSequences to search for, may be null
    2804     * @return the first index of any of the searchStrs in str, -1 if no match
    2805     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
    2806     */
    2807    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2808        if (str == null || searchStrs == null) {
    2809            return INDEX_NOT_FOUND;
    2810        }
    2811
    2812        // String's can't have a MAX_VALUEth index.
    2813        int ret = Integer.MAX_VALUE;
    2814
    2815        int tmp;
    2816        for (final CharSequence search : searchStrs) {
    2817            if (search == null) {
    2818                continue;
    2819            }
    2820            tmp = CharSequenceUtils.indexOf(str, search, 0);
    2821            if (tmp == INDEX_NOT_FOUND) {
    2822                continue;
    2823            }
    2824
    2825            if (tmp < ret) {
    2826                ret = tmp;
    2827            }
    2828        }
    2829
    2830        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
    2831    }
    2832
    2833    /**
    2834     * Search a CharSequence to find the first index of any
    2835     * character in the given set of characters.
    2836     *
    2837     * <p>A {@code null} String will return {@code -1}.
    2838     * A {@code null} search string will return {@code -1}.</p>
    2839     *
    2840     * <pre>
    2841     * StringUtils.indexOfAny(null, *)            = -1
    2842     * StringUtils.indexOfAny("", *)              = -1
    2843     * StringUtils.indexOfAny(*, null)            = -1
    2844     * StringUtils.indexOfAny(*, "")              = -1
    2845     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    2846     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    2847     * StringUtils.indexOfAny("aba", "z")         = -1
    2848     * </pre>
    2849     *
    2850     * @param cs  the CharSequence to check, may be null
    2851     * @param searchChars  the chars to search for, may be null
    2852     * @return the index of any of the chars, -1 if no match or null input
    2853     * @since 2.0
    2854     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    2855     */
    2856    public static int indexOfAny(final CharSequence cs, final String searchChars) {
    2857        if (isEmpty(cs) || isEmpty(searchChars)) {
    2858            return INDEX_NOT_FOUND;
    2859        }
    2860        return indexOfAny(cs, searchChars.toCharArray());
    2861    }
    2862
    2863    /**
    2864     * Searches a CharSequence to find the first index of any
    2865     * character not in the given set of characters.
    2866     *
    2867     * <p>A {@code null} CharSequence will return {@code -1}.
    2868     * A {@code null} or zero length search array will return {@code -1}.</p>
    2869     *
    2870     * <pre>
    2871     * StringUtils.indexOfAnyBut(null, *)                              = -1
    2872     * StringUtils.indexOfAnyBut("", *)                                = -1
    2873     * StringUtils.indexOfAnyBut(*, null)                              = -1
    2874     * StringUtils.indexOfAnyBut(*, [])                                = -1
    2875     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
    2876     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
    2877     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
    2878
    2879     * </pre>
    2880     *
    2881     * @param cs  the CharSequence to check, may be null
    2882     * @param searchChars  the chars to search for, may be null
    2883     * @return the index of any of the chars, -1 if no match or null input
    2884     * @since 2.0
    2885     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
    2886     */
    2887    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    2888        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2889            return INDEX_NOT_FOUND;
    2890        }
    2891        final int csLen = cs.length();
    2892        final int csLast = csLen - 1;
    2893        final int searchLen = searchChars.length;
    2894        final int searchLast = searchLen - 1;
    2895        outer:
    2896        for (int i = 0; i < csLen; i++) {
    2897            final char ch = cs.charAt(i);
    2898            for (int j = 0; j < searchLen; j++) {
    2899                if (searchChars[j] == ch) {
    2900                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
    2901                        continue outer;
    2902                    }
    2903                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2904                        continue outer;
    2905                    }
    2906                }
    2907            }
    2908            return i;
    2909        }
    2910        return INDEX_NOT_FOUND;
    2911    }
    2912
    2913    /**
    2914     * Search a CharSequence to find the first index of any
    2915     * character not in the given set of characters.
    2916     *
    2917     * <p>A {@code null} CharSequence will return {@code -1}.
    2918     * A {@code null} or empty search string will return {@code -1}.</p>
    2919     *
    2920     * <pre>
    2921     * StringUtils.indexOfAnyBut(null, *)            = -1
    2922     * StringUtils.indexOfAnyBut("", *)              = -1
    2923     * StringUtils.indexOfAnyBut(*, null)            = -1
    2924     * StringUtils.indexOfAnyBut(*, "")              = -1
    2925     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    2926     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
    2927     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
    2928     * </pre>
    2929     *
    2930     * @param seq  the CharSequence to check, may be null
    2931     * @param searchChars  the chars to search for, may be null
    2932     * @return the index of any of the chars, -1 if no match or null input
    2933     * @since 2.0
    2934     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
    2935     */
    2936    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
    2937        if (isEmpty(seq) || isEmpty(searchChars)) {
    2938            return INDEX_NOT_FOUND;
    2939        }
    2940        final int strLen = seq.length();
    2941        for (int i = 0; i < strLen; i++) {
    2942            final char ch = seq.charAt(i);
    2943            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
    2944            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
    2945                final char ch2 = seq.charAt(i + 1);
    2946                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
    2947                    return i;
    2948                }
    2949            } else if (!chFound) {
    2950                return i;
    2951            }
    2952        }
    2953        return INDEX_NOT_FOUND;
    2954    }
    2955
    2956    /**
    2957     * Compares all CharSequences in an array and returns the index at which the
    2958     * CharSequences begin to differ.
    2959     *
    2960     * <p>For example,
    2961     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
    2962     *
    2963     * <pre>
    2964     * StringUtils.indexOfDifference(null) = -1
    2965     * StringUtils.indexOfDifference(new String[] {}) = -1
    2966     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
    2967     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
    2968     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
    2969     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
    2970     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    2971     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    2972     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
    2973     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
    2974     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
    2975     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
    2976     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
    2977     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
    2978     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
    2979     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
    2980     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    2981     * </pre>
    2982     *
    2983     * @param css  array of CharSequences, entries may be null
    2984     * @return the index where the strings begin to differ; -1 if they are all equal
    2985     * @since 2.4
    2986     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    2987     */
    2988    public static int indexOfDifference(final CharSequence... css) {
    2989        if (ArrayUtils.getLength(css) <= 1) {
    2990            return INDEX_NOT_FOUND;
    2991        }
    2992        boolean anyStringNull = false;
    2993        boolean allStringsNull = true;
    2994        final int arrayLen = css.length;
    2995        int shortestStrLen = Integer.MAX_VALUE;
    2996        int longestStrLen = 0;
    2997
    2998        // find the min and max string lengths; this avoids checking to make
    2999        // sure we are not exceeding the length of the string each time through
    3000        // the bottom loop.
    3001        for (final CharSequence cs : css) {
    3002            if (cs == null) {
    3003                anyStringNull = true;
    3004                shortestStrLen = 0;
    3005            } else {
    3006                allStringsNull = false;
    3007                shortestStrLen = Math.min(cs.length(), shortestStrLen);
    3008                longestStrLen = Math.max(cs.length(), longestStrLen);
    3009            }
    3010        }
    3011
    3012        // handle lists containing all nulls or all empty strings
    3013        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
    3014            return INDEX_NOT_FOUND;
    3015        }
    3016
    3017        // handle lists containing some nulls or some empty strings
    3018        if (shortestStrLen == 0) {
    3019            return 0;
    3020        }
    3021
    3022        // find the position with the first difference across all strings
    3023        int firstDiff = -1;
    3024        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    3025            final char comparisonChar = css[0].charAt(stringPos);
    3026            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    3027                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    3028                    firstDiff = stringPos;
    3029                    break;
    3030                }
    3031            }
    3032            if (firstDiff != -1) {
    3033                break;
    3034            }
    3035        }
    3036
    3037        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    3038            // we compared all of the characters up to the length of the
    3039            // shortest string and didn't find a match, but the string lengths
    3040            // vary, so return the length of the shortest string.
    3041            return shortestStrLen;
    3042        }
    3043        return firstDiff;
    3044    }
    3045
    3046    /**
    3047     * Compares two CharSequences, and returns the index at which the
    3048     * CharSequences begin to differ.
    3049     *
    3050     * <p>For example,
    3051     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
    3052     *
    3053     * <pre>
    3054     * StringUtils.indexOfDifference(null, null) = -1
    3055     * StringUtils.indexOfDifference("", "") = -1
    3056     * StringUtils.indexOfDifference("", "abc") = 0
    3057     * StringUtils.indexOfDifference("abc", "") = 0
    3058     * StringUtils.indexOfDifference("abc", "abc") = -1
    3059     * StringUtils.indexOfDifference("ab", "abxyz") = 2
    3060     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    3061     * StringUtils.indexOfDifference("abcde", "xyz") = 0
    3062     * </pre>
    3063     *
    3064     * @param cs1  the first CharSequence, may be null
    3065     * @param cs2  the second CharSequence, may be null
    3066     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
    3067     * @since 2.0
    3068     * @since 3.0 Changed signature from indexOfDifference(String, String) to
    3069     * indexOfDifference(CharSequence, CharSequence)
    3070     */
    3071    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
    3072        if (cs1 == cs2) {
    3073            return INDEX_NOT_FOUND;
    3074        }
    3075        if (cs1 == null || cs2 == null) {
    3076            return 0;
    3077        }
    3078        int i;
    3079        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    3080            if (cs1.charAt(i) != cs2.charAt(i)) {
    3081                break;
    3082            }
    3083        }
    3084        if (i < cs2.length() || i < cs1.length()) {
    3085            return i;
    3086        }
    3087        return INDEX_NOT_FOUND;
    3088    }
    3089
    3090    /**
    3091     * Case in-sensitive find of the first index within a CharSequence.
    3092     *
    3093     * <p>A {@code null} CharSequence will return {@code -1}.
    3094     * A negative start position is treated as zero.
    3095     * An empty ("") search CharSequence always matches.
    3096     * A start position greater than the string length only matches
    3097     * an empty search CharSequence.</p>
    3098     *
    3099     * <pre>
    3100     * StringUtils.indexOfIgnoreCase(null, *)          = -1
    3101     * StringUtils.indexOfIgnoreCase(*, null)          = -1
    3102     * StringUtils.indexOfIgnoreCase("", "")           = 0
    3103     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
    3104     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    3105     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    3106     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    3107     * </pre>
    3108     *
    3109     * @param str  the CharSequence to check, may be null
    3110     * @param searchStr  the CharSequence to find, may be null
    3111     * @return the first index of the search CharSequence,
    3112     *  -1 if no match or {@code null} string input
    3113     * @since 2.5
    3114     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
    3115     */
    3116    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    3117        return indexOfIgnoreCase(str, searchStr, 0);
    3118    }
    3119
    3120    /**
    3121     * Case in-sensitive find of the first index within a CharSequence
    3122     * from the specified position.
    3123     *
    3124     * <p>A {@code null} CharSequence will return {@code -1}.
    3125     * A negative start position is treated as zero.
    3126     * An empty ("") search CharSequence always matches.
    3127     * A start position greater than the string length only matches
    3128     * an empty search CharSequence.</p>
    3129     *
    3130     * <pre>
    3131     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    3132     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    3133     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    3134     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    3135     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    3136     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    3137     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    3138     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    3139     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    3140     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    3141     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
    3142     * </pre>
    3143     *
    3144     * @param str  the CharSequence to check, may be null
    3145     * @param searchStr  the CharSequence to find, may be null
    3146     * @param startPos  the start position, negative treated as zero
    3147     * @return the first index of the search CharSequence (always &ge; startPos),
    3148     *  -1 if no match or {@code null} string input
    3149     * @since 2.5
    3150     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
    3151     */
    3152    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    3153        if (str == null || searchStr == null) {
    3154            return INDEX_NOT_FOUND;
    3155        }
    3156        if (startPos < 0) {
    3157            startPos = 0;
    3158        }
    3159        final int endLimit = str.length() - searchStr.length() + 1;
    3160        if (startPos > endLimit) {
    3161            return INDEX_NOT_FOUND;
    3162        }
    3163        if (searchStr.length() == 0) {
    3164            return startPos;
    3165        }
    3166        for (int i = startPos; i < endLimit; i++) {
    3167            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
    3168                return i;
    3169            }
    3170        }
    3171        return INDEX_NOT_FOUND;
    3172    }
    3173
    3174    /**
    3175     * Checks if all of the CharSequences are empty (""), null or whitespace only.
    3176     *
    3177     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3178     *
    3179     * <pre>
    3180     * StringUtils.isAllBlank(null)             = true
    3181     * StringUtils.isAllBlank(null, "foo")      = false
    3182     * StringUtils.isAllBlank(null, null)       = true
    3183     * StringUtils.isAllBlank("", "bar")        = false
    3184     * StringUtils.isAllBlank("bob", "")        = false
    3185     * StringUtils.isAllBlank("  bob  ", null)  = false
    3186     * StringUtils.isAllBlank(" ", "bar")       = false
    3187     * StringUtils.isAllBlank("foo", "bar")     = false
    3188     * StringUtils.isAllBlank(new String[] {})  = true
    3189     * </pre>
    3190     *
    3191     * @param css  the CharSequences to check, may be null or empty
    3192     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
    3193     * @since 3.6
    3194     */
    3195    public static boolean isAllBlank(final CharSequence... css) {
    3196        if (ArrayUtils.isEmpty(css)) {
    3197            return true;
    3198        }
    3199        for (final CharSequence cs : css) {
    3200            if (isNotBlank(cs)) {
    3201               return false;
    3202            }
    3203        }
    3204        return true;
    3205    }
    3206
    3207    /**
    3208     * Checks if all of the CharSequences are empty ("") or null.
    3209     *
    3210     * <pre>
    3211     * StringUtils.isAllEmpty(null)             = true
    3212     * StringUtils.isAllEmpty(null, "")         = true
    3213     * StringUtils.isAllEmpty(new String[] {})  = true
    3214     * StringUtils.isAllEmpty(null, "foo")      = false
    3215     * StringUtils.isAllEmpty("", "bar")        = false
    3216     * StringUtils.isAllEmpty("bob", "")        = false
    3217     * StringUtils.isAllEmpty("  bob  ", null)  = false
    3218     * StringUtils.isAllEmpty(" ", "bar")       = false
    3219     * StringUtils.isAllEmpty("foo", "bar")     = false
    3220     * </pre>
    3221     *
    3222     * @param css  the CharSequences to check, may be null or empty
    3223     * @return {@code true} if all of the CharSequences are empty or null
    3224     * @since 3.6
    3225     */
    3226    public static boolean isAllEmpty(final CharSequence... css) {
    3227        if (ArrayUtils.isEmpty(css)) {
    3228            return true;
    3229        }
    3230        for (final CharSequence cs : css) {
    3231            if (isNotEmpty(cs)) {
    3232                return false;
    3233            }
    3234        }
    3235        return true;
    3236    }
    3237
    3238    /**
    3239     * Checks if the CharSequence contains only lowercase characters.
    3240     *
    3241     * <p>{@code null} will return {@code false}.
    3242     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3243     *
    3244     * <pre>
    3245     * StringUtils.isAllLowerCase(null)   = false
    3246     * StringUtils.isAllLowerCase("")     = false
    3247     * StringUtils.isAllLowerCase("  ")   = false
    3248     * StringUtils.isAllLowerCase("abc")  = true
    3249     * StringUtils.isAllLowerCase("abC")  = false
    3250     * StringUtils.isAllLowerCase("ab c") = false
    3251     * StringUtils.isAllLowerCase("ab1c") = false
    3252     * StringUtils.isAllLowerCase("ab/c") = false
    3253     * </pre>
    3254     *
    3255     * @param cs  the CharSequence to check, may be null
    3256     * @return {@code true} if only contains lowercase characters, and is non-null
    3257     * @since 2.5
    3258     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    3259     */
    3260    public static boolean isAllLowerCase(final CharSequence cs) {
    3261        if (isEmpty(cs)) {
    3262            return false;
    3263        }
    3264        final int sz = cs.length();
    3265        for (int i = 0; i < sz; i++) {
    3266            if (!Character.isLowerCase(cs.charAt(i))) {
    3267                return false;
    3268            }
    3269        }
    3270        return true;
    3271    }
    3272
    3273    /**
    3274     * Checks if the CharSequence contains only uppercase characters.
    3275     *
    3276     * <p>{@code null} will return {@code false}.
    3277     * An empty String (length()=0) will return {@code false}.</p>
    3278     *
    3279     * <pre>
    3280     * StringUtils.isAllUpperCase(null)   = false
    3281     * StringUtils.isAllUpperCase("")     = false
    3282     * StringUtils.isAllUpperCase("  ")   = false
    3283     * StringUtils.isAllUpperCase("ABC")  = true
    3284     * StringUtils.isAllUpperCase("aBC")  = false
    3285     * StringUtils.isAllUpperCase("A C")  = false
    3286     * StringUtils.isAllUpperCase("A1C")  = false
    3287     * StringUtils.isAllUpperCase("A/C")  = false
    3288     * </pre>
    3289     *
    3290     * @param cs the CharSequence to check, may be null
    3291     * @return {@code true} if only contains uppercase characters, and is non-null
    3292     * @since 2.5
    3293     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    3294     */
    3295    public static boolean isAllUpperCase(final CharSequence cs) {
    3296        if (isEmpty(cs)) {
    3297            return false;
    3298        }
    3299        final int sz = cs.length();
    3300        for (int i = 0; i < sz; i++) {
    3301            if (!Character.isUpperCase(cs.charAt(i))) {
    3302                return false;
    3303            }
    3304        }
    3305        return true;
    3306    }
    3307
    3308    /**
    3309     * Checks if the CharSequence contains only Unicode letters.
    3310     *
    3311     * <p>{@code null} will return {@code false}.
    3312     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3313     *
    3314     * <pre>
    3315     * StringUtils.isAlpha(null)   = false
    3316     * StringUtils.isAlpha("")     = false
    3317     * StringUtils.isAlpha("  ")   = false
    3318     * StringUtils.isAlpha("abc")  = true
    3319     * StringUtils.isAlpha("ab2c") = false
    3320     * StringUtils.isAlpha("ab-c") = false
    3321     * </pre>
    3322     *
    3323     * @param cs  the CharSequence to check, may be null
    3324     * @return {@code true} if only contains letters, and is non-null
    3325     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    3326     * @since 3.0 Changed "" to return false and not true
    3327     */
    3328    public static boolean isAlpha(final CharSequence cs) {
    3329        if (isEmpty(cs)) {
    3330            return false;
    3331        }
    3332        final int sz = cs.length();
    3333        for (int i = 0; i < sz; i++) {
    3334            if (!Character.isLetter(cs.charAt(i))) {
    3335                return false;
    3336            }
    3337        }
    3338        return true;
    3339    }
    3340
    3341    /**
    3342     * Checks if the CharSequence contains only Unicode letters or digits.
    3343     *
    3344     * <p>{@code null} will return {@code false}.
    3345     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3346     *
    3347     * <pre>
    3348     * StringUtils.isAlphanumeric(null)   = false
    3349     * StringUtils.isAlphanumeric("")     = false
    3350     * StringUtils.isAlphanumeric("  ")   = false
    3351     * StringUtils.isAlphanumeric("abc")  = true
    3352     * StringUtils.isAlphanumeric("ab c") = false
    3353     * StringUtils.isAlphanumeric("ab2c") = true
    3354     * StringUtils.isAlphanumeric("ab-c") = false
    3355     * </pre>
    3356     *
    3357     * @param cs  the CharSequence to check, may be null
    3358     * @return {@code true} if only contains letters or digits,
    3359     *  and is non-null
    3360     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    3361     * @since 3.0 Changed "" to return false and not true
    3362     */
    3363    public static boolean isAlphanumeric(final CharSequence cs) {
    3364        if (isEmpty(cs)) {
    3365            return false;
    3366        }
    3367        final int sz = cs.length();
    3368        for (int i = 0; i < sz; i++) {
    3369            if (!Character.isLetterOrDigit(cs.charAt(i))) {
    3370                return false;
    3371            }
    3372        }
    3373        return true;
    3374    }
    3375
    3376    /**
    3377     * Checks if the CharSequence contains only Unicode letters, digits
    3378     * or space ({@code ' '}).
    3379     *
    3380     * <p>{@code null} will return {@code false}.
    3381     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3382     *
    3383     * <pre>
    3384     * StringUtils.isAlphanumericSpace(null)   = false
    3385     * StringUtils.isAlphanumericSpace("")     = true
    3386     * StringUtils.isAlphanumericSpace("  ")   = true
    3387     * StringUtils.isAlphanumericSpace("abc")  = true
    3388     * StringUtils.isAlphanumericSpace("ab c") = true
    3389     * StringUtils.isAlphanumericSpace("ab2c") = true
    3390     * StringUtils.isAlphanumericSpace("ab-c") = false
    3391     * </pre>
    3392     *
    3393     * @param cs  the CharSequence to check, may be null
    3394     * @return {@code true} if only contains letters, digits or space,
    3395     *  and is non-null
    3396     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    3397     */
    3398    public static boolean isAlphanumericSpace(final CharSequence cs) {
    3399        if (cs == null) {
    3400            return false;
    3401        }
    3402        final int sz = cs.length();
    3403        for (int i = 0; i < sz; i++) {
    3404            final char nowChar = cs.charAt(i);
    3405            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) {
    3406                return false;
    3407            }
    3408        }
    3409        return true;
    3410    }
    3411
    3412    /**
    3413     * Checks if the CharSequence contains only Unicode letters and
    3414     * space (' ').
    3415     *
    3416     * <p>{@code null} will return {@code false}
    3417     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3418     *
    3419     * <pre>
    3420     * StringUtils.isAlphaSpace(null)   = false
    3421     * StringUtils.isAlphaSpace("")     = true
    3422     * StringUtils.isAlphaSpace("  ")   = true
    3423     * StringUtils.isAlphaSpace("abc")  = true
    3424     * StringUtils.isAlphaSpace("ab c") = true
    3425     * StringUtils.isAlphaSpace("ab2c") = false
    3426     * StringUtils.isAlphaSpace("ab-c") = false
    3427     * </pre>
    3428     *
    3429     * @param cs  the CharSequence to check, may be null
    3430     * @return {@code true} if only contains letters and space,
    3431     *  and is non-null
    3432     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    3433     */
    3434    public static boolean isAlphaSpace(final CharSequence cs) {
    3435        if (cs == null) {
    3436            return false;
    3437        }
    3438        final int sz = cs.length();
    3439        for (int i = 0; i < sz; i++) {
    3440            final char nowChar = cs.charAt(i);
    3441            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
    3442                return false;
    3443            }
    3444        }
    3445        return true;
    3446    }
    3447
    3448    /**
    3449     * Checks if any of the CharSequences are empty ("") or null or whitespace only.
    3450     *
    3451     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3452     *
    3453     * <pre>
    3454     * StringUtils.isAnyBlank((String) null)    = true
    3455     * StringUtils.isAnyBlank((String[]) null)  = false
    3456     * StringUtils.isAnyBlank(null, "foo")      = true
    3457     * StringUtils.isAnyBlank(null, null)       = true
    3458     * StringUtils.isAnyBlank("", "bar")        = true
    3459     * StringUtils.isAnyBlank("bob", "")        = true
    3460     * StringUtils.isAnyBlank("  bob  ", null)  = true
    3461     * StringUtils.isAnyBlank(" ", "bar")       = true
    3462     * StringUtils.isAnyBlank(new String[] {})  = false
    3463     * StringUtils.isAnyBlank(new String[]{""}) = true
    3464     * StringUtils.isAnyBlank("foo", "bar")     = false
    3465     * </pre>
    3466     *
    3467     * @param css  the CharSequences to check, may be null or empty
    3468     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
    3469     * @since 3.2
    3470     */
    3471    public static boolean isAnyBlank(final CharSequence... css) {
    3472        if (ArrayUtils.isEmpty(css)) {
    3473            return false;
    3474        }
    3475        for (final CharSequence cs : css) {
    3476            if (isBlank(cs)) {
    3477                return true;
    3478            }
    3479        }
    3480        return false;
    3481    }
    3482
    3483    /**
    3484     * Checks if any of the CharSequences are empty ("") or null.
    3485     *
    3486     * <pre>
    3487     * StringUtils.isAnyEmpty((String) null)    = true
    3488     * StringUtils.isAnyEmpty((String[]) null)  = false
    3489     * StringUtils.isAnyEmpty(null, "foo")      = true
    3490     * StringUtils.isAnyEmpty("", "bar")        = true
    3491     * StringUtils.isAnyEmpty("bob", "")        = true
    3492     * StringUtils.isAnyEmpty("  bob  ", null)  = true
    3493     * StringUtils.isAnyEmpty(" ", "bar")       = false
    3494     * StringUtils.isAnyEmpty("foo", "bar")     = false
    3495     * StringUtils.isAnyEmpty(new String[]{})   = false
    3496     * StringUtils.isAnyEmpty(new String[]{""}) = true
    3497     * </pre>
    3498     *
    3499     * @param css  the CharSequences to check, may be null or empty
    3500     * @return {@code true} if any of the CharSequences are empty or null
    3501     * @since 3.2
    3502     */
    3503    public static boolean isAnyEmpty(final CharSequence... css) {
    3504        if (ArrayUtils.isEmpty(css)) {
    3505            return false;
    3506        }
    3507        for (final CharSequence cs : css) {
    3508            if (isEmpty(cs)) {
    3509                return true;
    3510            }
    3511        }
    3512        return false;
    3513    }
    3514
    3515    /**
    3516     * Checks if the CharSequence contains only ASCII printable characters.
    3517     *
    3518     * <p>{@code null} will return {@code false}.
    3519     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3520     *
    3521     * <pre>
    3522     * StringUtils.isAsciiPrintable(null)     = false
    3523     * StringUtils.isAsciiPrintable("")       = true
    3524     * StringUtils.isAsciiPrintable(" ")      = true
    3525     * StringUtils.isAsciiPrintable("Ceki")   = true
    3526     * StringUtils.isAsciiPrintable("ab2c")   = true
    3527     * StringUtils.isAsciiPrintable("!ab-c~") = true
    3528     * StringUtils.isAsciiPrintable("\u0020") = true
    3529     * StringUtils.isAsciiPrintable("\u0021") = true
    3530     * StringUtils.isAsciiPrintable("\u007e") = true
    3531     * StringUtils.isAsciiPrintable("\u007f") = false
    3532     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    3533     * </pre>
    3534     *
    3535     * @param cs the CharSequence to check, may be null
    3536     * @return {@code true} if every character is in the range
    3537     *  32 through 126
    3538     * @since 2.1
    3539     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    3540     */
    3541    public static boolean isAsciiPrintable(final CharSequence cs) {
    3542        if (cs == null) {
    3543            return false;
    3544        }
    3545        final int sz = cs.length();
    3546        for (int i = 0; i < sz; i++) {
    3547            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
    3548                return false;
    3549            }
    3550        }
    3551        return true;
    3552    }
    3553
    3554    /**
    3555     * Checks if a CharSequence is empty (""), null or whitespace only.
    3556     *
    3557     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3558     *
    3559     * <pre>
    3560     * StringUtils.isBlank(null)      = true
    3561     * StringUtils.isBlank("")        = true
    3562     * StringUtils.isBlank(" ")       = true
    3563     * StringUtils.isBlank("bob")     = false
    3564     * StringUtils.isBlank("  bob  ") = false
    3565     * </pre>
    3566     *
    3567     * @param cs  the CharSequence to check, may be null
    3568     * @return {@code true} if the CharSequence is null, empty or whitespace only
    3569     * @since 2.0
    3570     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    3571     */
    3572    public static boolean isBlank(final CharSequence cs) {
    3573        final int strLen = length(cs);
    3574        if (strLen == 0) {
    3575            return true;
    3576        }
    3577        for (int i = 0; i < strLen; i++) {
    3578            if (!Character.isWhitespace(cs.charAt(i))) {
    3579                return false;
    3580            }
    3581        }
    3582        return true;
    3583    }
    3584
    3585    /**
    3586     * Checks if a CharSequence is empty ("") or null.
    3587     *
    3588     * <pre>
    3589     * StringUtils.isEmpty(null)      = true
    3590     * StringUtils.isEmpty("")        = true
    3591     * StringUtils.isEmpty(" ")       = false
    3592     * StringUtils.isEmpty("bob")     = false
    3593     * StringUtils.isEmpty("  bob  ") = false
    3594     * </pre>
    3595     *
    3596     * <p>NOTE: This method changed in Lang version 2.0.
    3597     * It no longer trims the CharSequence.
    3598     * That functionality is available in isBlank().</p>
    3599     *
    3600     * @param cs  the CharSequence to check, may be null
    3601     * @return {@code true} if the CharSequence is empty or null
    3602     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    3603     */
    3604    public static boolean isEmpty(final CharSequence cs) {
    3605        return cs == null || cs.length() == 0;
    3606    }
    3607
    3608    /**
    3609     * Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.
    3610     *
    3611     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
    3612     * {@code false}.</p>
    3613     *
    3614     * <pre>
    3615     * StringUtils.isMixedCase(null)    = false
    3616     * StringUtils.isMixedCase("")      = false
    3617     * StringUtils.isMixedCase(" ")     = false
    3618     * StringUtils.isMixedCase("ABC")   = false
    3619     * StringUtils.isMixedCase("abc")   = false
    3620     * StringUtils.isMixedCase("aBc")   = true
    3621     * StringUtils.isMixedCase("A c")   = true
    3622     * StringUtils.isMixedCase("A1c")   = true
    3623     * StringUtils.isMixedCase("a/C")   = true
    3624     * StringUtils.isMixedCase("aC\t")  = true
    3625     * </pre>
    3626     *
    3627     * @param cs the CharSequence to check, may be null
    3628     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
    3629     * @since 3.5
    3630     */
    3631    public static boolean isMixedCase(final CharSequence cs) {
    3632        if (isEmpty(cs) || cs.length() == 1) {
    3633            return false;
    3634        }
    3635        boolean containsUppercase = false;
    3636        boolean containsLowercase = false;
    3637        final int sz = cs.length();
    3638        for (int i = 0; i < sz; i++) {
    3639            final char nowChar = cs.charAt(i);
    3640            if (Character.isUpperCase(nowChar)) {
    3641                containsUppercase = true;
    3642            } else if (Character.isLowerCase(nowChar)) {
    3643                containsLowercase = true;
    3644            }
    3645            if (containsUppercase && containsLowercase) {
    3646                return true;
    3647            }
    3648        }
    3649        return false;
    3650    }
    3651
    3652    /**
    3653     * Checks if none of the CharSequences are empty (""), null or whitespace only.
    3654     *
    3655     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3656     *
    3657     * <pre>
    3658     * StringUtils.isNoneBlank((String) null)    = false
    3659     * StringUtils.isNoneBlank((String[]) null)  = true
    3660     * StringUtils.isNoneBlank(null, "foo")      = false
    3661     * StringUtils.isNoneBlank(null, null)       = false
    3662     * StringUtils.isNoneBlank("", "bar")        = false
    3663     * StringUtils.isNoneBlank("bob", "")        = false
    3664     * StringUtils.isNoneBlank("  bob  ", null)  = false
    3665     * StringUtils.isNoneBlank(" ", "bar")       = false
    3666     * StringUtils.isNoneBlank(new String[] {})  = true
    3667     * StringUtils.isNoneBlank(new String[]{""}) = false
    3668     * StringUtils.isNoneBlank("foo", "bar")     = true
    3669     * </pre>
    3670     *
    3671     * @param css  the CharSequences to check, may be null or empty
    3672     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
    3673     * @since 3.2
    3674     */
    3675    public static boolean isNoneBlank(final CharSequence... css) {
    3676      return !isAnyBlank(css);
    3677    }
    3678
    3679    /**
    3680     * Checks if none of the CharSequences are empty ("") or null.
    3681     *
    3682     * <pre>
    3683     * StringUtils.isNoneEmpty((String) null)    = false
    3684     * StringUtils.isNoneEmpty((String[]) null)  = true
    3685     * StringUtils.isNoneEmpty(null, "foo")      = false
    3686     * StringUtils.isNoneEmpty("", "bar")        = false
    3687     * StringUtils.isNoneEmpty("bob", "")        = false
    3688     * StringUtils.isNoneEmpty("  bob  ", null)  = false
    3689     * StringUtils.isNoneEmpty(new String[] {})  = true
    3690     * StringUtils.isNoneEmpty(new String[]{""}) = false
    3691     * StringUtils.isNoneEmpty(" ", "bar")       = true
    3692     * StringUtils.isNoneEmpty("foo", "bar")     = true
    3693     * </pre>
    3694     *
    3695     * @param css  the CharSequences to check, may be null or empty
    3696     * @return {@code true} if none of the CharSequences are empty or null
    3697     * @since 3.2
    3698     */
    3699    public static boolean isNoneEmpty(final CharSequence... css) {
    3700      return !isAnyEmpty(css);
    3701    }
    3702
    3703    /**
    3704     * Checks if a CharSequence is not empty (""), not null and not whitespace only.
    3705     *
    3706     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3707     *
    3708     * <pre>
    3709     * StringUtils.isNotBlank(null)      = false
    3710     * StringUtils.isNotBlank("")        = false
    3711     * StringUtils.isNotBlank(" ")       = false
    3712     * StringUtils.isNotBlank("bob")     = true
    3713     * StringUtils.isNotBlank("  bob  ") = true
    3714     * </pre>
    3715     *
    3716     * @param cs  the CharSequence to check, may be null
    3717     * @return {@code true} if the CharSequence is
    3718     *  not empty and not null and not whitespace only
    3719     * @since 2.0
    3720     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    3721     */
    3722    public static boolean isNotBlank(final CharSequence cs) {
    3723        return !isBlank(cs);
    3724    }
    3725
    3726    /**
    3727     * Checks if a CharSequence is not empty ("") and not null.
    3728     *
    3729     * <pre>
    3730     * StringUtils.isNotEmpty(null)      = false
    3731     * StringUtils.isNotEmpty("")        = false
    3732     * StringUtils.isNotEmpty(" ")       = true
    3733     * StringUtils.isNotEmpty("bob")     = true
    3734     * StringUtils.isNotEmpty("  bob  ") = true
    3735     * </pre>
    3736     *
    3737     * @param cs  the CharSequence to check, may be null
    3738     * @return {@code true} if the CharSequence is not empty and not null
    3739     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    3740     */
    3741    public static boolean isNotEmpty(final CharSequence cs) {
    3742        return !isEmpty(cs);
    3743    }
    3744
    3745    /**
    3746     * Checks if the CharSequence contains only Unicode digits.
    3747     * A decimal point is not a Unicode digit and returns false.
    3748     *
    3749     * <p>{@code null} will return {@code false}.
    3750     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3751     *
    3752     * <p>Note that the method does not allow for a leading sign, either positive or negative.
    3753     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
    3754     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
    3755     * for int or long respectively.</p>
    3756     *
    3757     * <pre>
    3758     * StringUtils.isNumeric(null)   = false
    3759     * StringUtils.isNumeric("")     = false
    3760     * StringUtils.isNumeric("  ")   = false
    3761     * StringUtils.isNumeric("123")  = true
    3762     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    3763     * StringUtils.isNumeric("12 3") = false
    3764     * StringUtils.isNumeric("ab2c") = false
    3765     * StringUtils.isNumeric("12-3") = false
    3766     * StringUtils.isNumeric("12.3") = false
    3767     * StringUtils.isNumeric("-123") = false
    3768     * StringUtils.isNumeric("+123") = false
    3769     * </pre>
    3770     *
    3771     * @param cs  the CharSequence to check, may be null
    3772     * @return {@code true} if only contains digits, and is non-null
    3773     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    3774     * @since 3.0 Changed "" to return false and not true
    3775     */
    3776    public static boolean isNumeric(final CharSequence cs) {
    3777        if (isEmpty(cs)) {
    3778            return false;
    3779        }
    3780        final int sz = cs.length();
    3781        for (int i = 0; i < sz; i++) {
    3782            if (!Character.isDigit(cs.charAt(i))) {
    3783                return false;
    3784            }
    3785        }
    3786        return true;
    3787    }
    3788
    3789    /**
    3790     * Checks if the CharSequence contains only Unicode digits or space
    3791     * ({@code ' '}).
    3792     * A decimal point is not a Unicode digit and returns false.
    3793     *
    3794     * <p>{@code null} will return {@code false}.
    3795     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3796     *
    3797     * <pre>
    3798     * StringUtils.isNumericSpace(null)   = false
    3799     * StringUtils.isNumericSpace("")     = true
    3800     * StringUtils.isNumericSpace("  ")   = true
    3801     * StringUtils.isNumericSpace("123")  = true
    3802     * StringUtils.isNumericSpace("12 3") = true
    3803     * StringUtils.isNumericSpace("\u0967\u0968\u0969")  = true
    3804     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
    3805     * StringUtils.isNumericSpace("ab2c") = false
    3806     * StringUtils.isNumericSpace("12-3") = false
    3807     * StringUtils.isNumericSpace("12.3") = false
    3808     * </pre>
    3809     *
    3810     * @param cs  the CharSequence to check, may be null
    3811     * @return {@code true} if only contains digits or space,
    3812     *  and is non-null
    3813     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    3814     */
    3815    public static boolean isNumericSpace(final CharSequence cs) {
    3816        if (cs == null) {
    3817            return false;
    3818        }
    3819        final int sz = cs.length();
    3820        for (int i = 0; i < sz; i++) {
    3821            final char nowChar = cs.charAt(i);
    3822            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
    3823                return false;
    3824            }
    3825        }
    3826        return true;
    3827    }
    3828
    3829    /**
    3830     * Checks if the CharSequence contains only whitespace.
    3831     *
    3832     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3833     *
    3834     * <p>{@code null} will return {@code false}.
    3835     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3836     *
    3837     * <pre>
    3838     * StringUtils.isWhitespace(null)   = false
    3839     * StringUtils.isWhitespace("")     = true
    3840     * StringUtils.isWhitespace("  ")   = true
    3841     * StringUtils.isWhitespace("abc")  = false
    3842     * StringUtils.isWhitespace("ab2c") = false
    3843     * StringUtils.isWhitespace("ab-c") = false
    3844     * </pre>
    3845     *
    3846     * @param cs  the CharSequence to check, may be null
    3847     * @return {@code true} if only contains whitespace, and is non-null
    3848     * @since 2.0
    3849     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    3850     */
    3851    public static boolean isWhitespace(final CharSequence cs) {
    3852        if (cs == null) {
    3853            return false;
    3854        }
    3855        final int sz = cs.length();
    3856        for (int i = 0; i < sz; i++) {
    3857            if (!Character.isWhitespace(cs.charAt(i))) {
    3858                return false;
    3859            }
    3860        }
    3861        return true;
    3862    }
    3863
    3864    /**
    3865     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3866     *
    3867     * <p>
    3868     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3869     * by empty strings.
    3870     * </p>
    3871     *
    3872     * <pre>
    3873     * StringUtils.join(null, *)              = null
    3874     * StringUtils.join([], *)                = ""
    3875     * StringUtils.join([null], *)            = ""
    3876     * StringUtils.join([false, false], ';')  = "false;false"
    3877     * </pre>
    3878     *
    3879     * @param array
    3880     *            the array of values to join together, may be null
    3881     * @param delimiter
    3882     *            the separator character to use
    3883     * @return the joined String, {@code null} if null array input
    3884     * @since 3.12.0
    3885     */
    3886    public static String join(final boolean[] array, final char delimiter) {
    3887        if (array == null) {
    3888            return null;
    3889        }
    3890        return join(array, delimiter, 0, array.length);
    3891    }
    3892
    3893    /**
    3894     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3895     *
    3896     * <p>
    3897     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3898     * by empty strings.
    3899     * </p>
    3900     *
    3901     * <pre>
    3902     * StringUtils.join(null, *)                   = null
    3903     * StringUtils.join([], *)                     = ""
    3904     * StringUtils.join([null], *)                 = ""
    3905     * StringUtils.join([true, false, true], ';')  = "true;false;true"
    3906     * </pre>
    3907     *
    3908     * @param array
    3909     *            the array of values to join together, may be null
    3910     * @param delimiter
    3911     *            the separator character to use
    3912     * @param startIndex
    3913     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3914     *            array
    3915     * @param endIndex
    3916     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3917     *            the array
    3918     * @return the joined String, {@code null} if null array input
    3919     * @since 3.12.0
    3920     */
    3921    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
    3922        if (array == null) {
    3923            return null;
    3924        }
    3925        if (endIndex - startIndex <= 0) {
    3926            return EMPTY;
    3927        }
    3928        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
    3929        for (int i = startIndex; i < endIndex; i++) {
    3930            stringBuilder
    3931                    .append(array[i])
    3932                    .append(delimiter);
    3933        }
    3934        return stringBuilder.substring(0, stringBuilder.length() - 1);
    3935    }
    3936
    3937    /**
    3938     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3939     *
    3940     * <p>
    3941     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3942     * by empty strings.
    3943     * </p>
    3944     *
    3945     * <pre>
    3946     * StringUtils.join(null, *)               = null
    3947     * StringUtils.join([], *)                 = ""
    3948     * StringUtils.join([null], *)             = ""
    3949     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3950     * StringUtils.join([1, 2, 3], null) = "123"
    3951     * </pre>
    3952     *
    3953     * @param array
    3954     *            the array of values to join together, may be null
    3955     * @param delimiter
    3956     *            the separator character to use
    3957     * @return the joined String, {@code null} if null array input
    3958     * @since 3.2
    3959     */
    3960    public static String join(final byte[] array, final char delimiter) {
    3961        if (array == null) {
    3962            return null;
    3963        }
    3964        return join(array, delimiter, 0, array.length);
    3965    }
    3966
    3967    /**
    3968     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3969     *
    3970     * <p>
    3971     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3972     * by empty strings.
    3973     * </p>
    3974     *
    3975     * <pre>
    3976     * StringUtils.join(null, *)               = null
    3977     * StringUtils.join([], *)                 = ""
    3978     * StringUtils.join([null], *)             = ""
    3979     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3980     * StringUtils.join([1, 2, 3], null) = "123"
    3981     * </pre>
    3982     *
    3983     * @param array
    3984     *            the array of values to join together, may be null
    3985     * @param delimiter
    3986     *            the separator character to use
    3987     * @param startIndex
    3988     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3989     *            array
    3990     * @param endIndex
    3991     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3992     *            the array
    3993     * @return the joined String, {@code null} if null array input
    3994     * @since 3.2
    3995     */
    3996    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
    3997        if (array == null) {
    3998            return null;
    3999        }
    4000        if (endIndex - startIndex <= 0) {
    4001            return EMPTY;
    4002        }
    4003        final StringBuilder stringBuilder = new StringBuilder();
    4004        for (int i = startIndex; i < endIndex; i++) {
    4005            stringBuilder
    4006                    .append(array[i])
    4007                    .append(delimiter);
    4008        }
    4009        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4010    }
    4011
    4012    /**
    4013     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4014     *
    4015     * <p>
    4016     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4017     * by empty strings.
    4018     * </p>
    4019     *
    4020     * <pre>
    4021     * StringUtils.join(null, *)               = null
    4022     * StringUtils.join([], *)                 = ""
    4023     * StringUtils.join([null], *)             = ""
    4024     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4025     * StringUtils.join([1, 2, 3], null) = "123"
    4026     * </pre>
    4027     *
    4028     * @param array
    4029     *            the array of values to join together, may be null
    4030     * @param delimiter
    4031     *            the separator character to use
    4032     * @return the joined String, {@code null} if null array input
    4033     * @since 3.2
    4034     */
    4035    public static String join(final char[] array, final char delimiter) {
    4036        if (array == null) {
    4037            return null;
    4038        }
    4039        return join(array, delimiter, 0, array.length);
    4040    }
    4041
    4042    /**
    4043     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4044     *
    4045     * <p>
    4046     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4047     * by empty strings.
    4048     * </p>
    4049     *
    4050     * <pre>
    4051     * StringUtils.join(null, *)               = null
    4052     * StringUtils.join([], *)                 = ""
    4053     * StringUtils.join([null], *)             = ""
    4054     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4055     * StringUtils.join([1, 2, 3], null) = "123"
    4056     * </pre>
    4057     *
    4058     * @param array
    4059     *            the array of values to join together, may be null
    4060     * @param delimiter
    4061     *            the separator character to use
    4062     * @param startIndex
    4063     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4064     *            array
    4065     * @param endIndex
    4066     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4067     *            the array
    4068     * @return the joined String, {@code null} if null array input
    4069     * @since 3.2
    4070     */
    4071    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
    4072        if (array == null) {
    4073            return null;
    4074        }
    4075        if (endIndex - startIndex <= 0) {
    4076            return EMPTY;
    4077        }
    4078        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
    4079        for (int i = startIndex; i < endIndex; i++) {
    4080            stringBuilder
    4081                    .append(array[i])
    4082                    .append(delimiter);
    4083        }
    4084        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4085    }
    4086
    4087    /**
    4088     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4089     *
    4090     * <p>
    4091     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4092     * by empty strings.
    4093     * </p>
    4094     *
    4095     * <pre>
    4096     * StringUtils.join(null, *)               = null
    4097     * StringUtils.join([], *)                 = ""
    4098     * StringUtils.join([null], *)             = ""
    4099     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4100     * StringUtils.join([1, 2, 3], null) = "123"
    4101     * </pre>
    4102     *
    4103     * @param array
    4104     *            the array of values to join together, may be null
    4105     * @param delimiter
    4106     *            the separator character to use
    4107     * @return the joined String, {@code null} if null array input
    4108     * @since 3.2
    4109     */
    4110    public static String join(final double[] array, final char delimiter) {
    4111        if (array == null) {
    4112            return null;
    4113        }
    4114        return join(array, delimiter, 0, array.length);
    4115    }
    4116
    4117    /**
    4118     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4119     *
    4120     * <p>
    4121     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4122     * by empty strings.
    4123     * </p>
    4124     *
    4125     * <pre>
    4126     * StringUtils.join(null, *)               = null
    4127     * StringUtils.join([], *)                 = ""
    4128     * StringUtils.join([null], *)             = ""
    4129     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4130     * StringUtils.join([1, 2, 3], null) = "123"
    4131     * </pre>
    4132     *
    4133     * @param array
    4134     *            the array of values to join together, may be null
    4135     * @param delimiter
    4136     *            the separator character to use
    4137     * @param startIndex
    4138     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4139     *            array
    4140     * @param endIndex
    4141     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4142     *            the array
    4143     * @return the joined String, {@code null} if null array input
    4144     * @since 3.2
    4145     */
    4146    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
    4147        if (array == null) {
    4148            return null;
    4149        }
    4150        if (endIndex - startIndex <= 0) {
    4151            return EMPTY;
    4152        }
    4153        final StringBuilder stringBuilder = new StringBuilder();
    4154        for (int i = startIndex; i < endIndex; i++) {
    4155            stringBuilder
    4156                    .append(array[i])
    4157                    .append(delimiter);
    4158        }
    4159        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4160    }
    4161
    4162    /**
    4163     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4164     *
    4165     * <p>
    4166     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4167     * by empty strings.
    4168     * </p>
    4169     *
    4170     * <pre>
    4171     * StringUtils.join(null, *)               = null
    4172     * StringUtils.join([], *)                 = ""
    4173     * StringUtils.join([null], *)             = ""
    4174     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4175     * StringUtils.join([1, 2, 3], null) = "123"
    4176     * </pre>
    4177     *
    4178     * @param array
    4179     *            the array of values to join together, may be null
    4180     * @param delimiter
    4181     *            the separator character to use
    4182     * @return the joined String, {@code null} if null array input
    4183     * @since 3.2
    4184     */
    4185    public static String join(final float[] array, final char delimiter) {
    4186        if (array == null) {
    4187            return null;
    4188        }
    4189        return join(array, delimiter, 0, array.length);
    4190    }
    4191
    4192    /**
    4193     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4194     *
    4195     * <p>
    4196     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4197     * by empty strings.
    4198     * </p>
    4199     *
    4200     * <pre>
    4201     * StringUtils.join(null, *)               = null
    4202     * StringUtils.join([], *)                 = ""
    4203     * StringUtils.join([null], *)             = ""
    4204     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4205     * StringUtils.join([1, 2, 3], null) = "123"
    4206     * </pre>
    4207     *
    4208     * @param array
    4209     *            the array of values to join together, may be null
    4210     * @param delimiter
    4211     *            the separator character to use
    4212     * @param startIndex
    4213     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4214     *            array
    4215     * @param endIndex
    4216     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4217     *            the array
    4218     * @return the joined String, {@code null} if null array input
    4219     * @since 3.2
    4220     */
    4221    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
    4222        if (array == null) {
    4223            return null;
    4224        }
    4225        if (endIndex - startIndex <= 0) {
    4226            return EMPTY;
    4227        }
    4228        final StringBuilder stringBuilder = new StringBuilder();
    4229        for (int i = startIndex; i < endIndex; i++) {
    4230            stringBuilder
    4231                    .append(array[i])
    4232                    .append(delimiter);
    4233        }
    4234        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4235    }
    4236
    4237    /**
    4238     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4239     *
    4240     * <p>
    4241     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4242     * by empty strings.
    4243     * </p>
    4244     *
    4245     * <pre>
    4246     * StringUtils.join(null, *)               = null
    4247     * StringUtils.join([], *)                 = ""
    4248     * StringUtils.join([null], *)             = ""
    4249     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4250     * StringUtils.join([1, 2, 3], null) = "123"
    4251     * </pre>
    4252     *
    4253     * @param array
    4254     *            the array of values to join together, may be null
    4255     * @param separator
    4256     *            the separator character to use
    4257     * @return the joined String, {@code null} if null array input
    4258     * @since 3.2
    4259     */
    4260    public static String join(final int[] array, final char separator) {
    4261        if (array == null) {
    4262            return null;
    4263        }
    4264        return join(array, separator, 0, array.length);
    4265    }
    4266
    4267    /**
    4268     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4269     *
    4270     * <p>
    4271     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4272     * by empty strings.
    4273     * </p>
    4274     *
    4275     * <pre>
    4276     * StringUtils.join(null, *)               = null
    4277     * StringUtils.join([], *)                 = ""
    4278     * StringUtils.join([null], *)             = ""
    4279     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4280     * StringUtils.join([1, 2, 3], null) = "123"
    4281     * </pre>
    4282     *
    4283     * @param array
    4284     *            the array of values to join together, may be null
    4285     * @param delimiter
    4286     *            the separator character to use
    4287     * @param startIndex
    4288     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4289     *            array
    4290     * @param endIndex
    4291     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4292     *            the array
    4293     * @return the joined String, {@code null} if null array input
    4294     * @since 3.2
    4295     */
    4296    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
    4297        if (array == null) {
    4298            return null;
    4299        }
    4300        if (endIndex - startIndex <= 0) {
    4301            return EMPTY;
    4302        }
    4303        final StringBuilder stringBuilder = new StringBuilder();
    4304        for (int i = startIndex; i < endIndex; i++) {
    4305            stringBuilder
    4306                    .append(array[i])
    4307                    .append(delimiter);
    4308        }
    4309        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4310    }
    4311
    4312    /**
    4313     * Joins the elements of the provided {@link Iterable} into
    4314     * a single String containing the provided elements.
    4315     *
    4316     * <p>No delimiter is added before or after the list. Null objects or empty
    4317     * strings within the iteration are represented by empty strings.</p>
    4318     *
    4319     * <p>See the examples here: {@link #join(Object[],char)}.</p>
    4320     *
    4321     * @param iterable  the {@link Iterable} providing the values to join together, may be null
    4322     * @param separator  the separator character to use
    4323     * @return the joined String, {@code null} if null iterator input
    4324     * @since 2.3
    4325     */
    4326    public static String join(final Iterable<?> iterable, final char separator) {
    4327        return iterable != null ? join(iterable.iterator(), separator) : null;
    4328    }
    4329
    4330    /**
    4331     * Joins the elements of the provided {@link Iterable} into
    4332     * a single String containing the provided elements.
    4333     *
    4334     * <p>No delimiter is added before or after the list.
    4335     * A {@code null} separator is the same as an empty String ("").</p>
    4336     *
    4337     * <p>See the examples here: {@link #join(Object[],String)}.</p>
    4338     *
    4339     * @param iterable  the {@link Iterable} providing the values to join together, may be null
    4340     * @param separator  the separator character to use, null treated as ""
    4341     * @return the joined String, {@code null} if null iterator input
    4342     * @since 2.3
    4343     */
    4344    public static String join(final Iterable<?> iterable, final String separator) {
    4345        return iterable != null ? join(iterable.iterator(), separator) : null;
    4346    }
    4347
    4348    /**
    4349     * Joins the elements of the provided {@link Iterator} into
    4350     * a single String containing the provided elements.
    4351     *
    4352     * <p>No delimiter is added before or after the list. Null objects or empty
    4353     * strings within the iteration are represented by empty strings.</p>
    4354     *
    4355     * <p>See the examples here: {@link #join(Object[],char)}.</p>
    4356     *
    4357     * @param iterator  the {@link Iterator} of values to join together, may be null
    4358     * @param separator  the separator character to use
    4359     * @return the joined String, {@code null} if null iterator input
    4360     * @since 2.0
    4361     */
    4362    public static String join(final Iterator<?> iterator, final char separator) {
    4363        // handle null, zero and one elements before building a buffer
    4364        if (iterator == null) {
    4365            return null;
    4366        }
    4367        if (!iterator.hasNext()) {
    4368            return EMPTY;
    4369        }
    4370        return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(String.valueOf(separator)), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
    4371    }
    4372
    4373    /**
    4374     * Joins the elements of the provided {@link Iterator} into
    4375     * a single String containing the provided elements.
    4376     *
    4377     * <p>No delimiter is added before or after the list.
    4378     * A {@code null} separator is the same as an empty String ("").</p>
    4379     *
    4380     * <p>See the examples here: {@link #join(Object[],String)}.</p>
    4381     *
    4382     * @param iterator  the {@link Iterator} of values to join together, may be null
    4383     * @param separator  the separator character to use, null treated as ""
    4384     * @return the joined String, {@code null} if null iterator input
    4385     */
    4386    public static String join(final Iterator<?> iterator, final String separator) {
    4387        // handle null, zero and one elements before building a buffer
    4388        if (iterator == null) {
    4389            return null;
    4390        }
    4391        if (!iterator.hasNext()) {
    4392            return EMPTY;
    4393        }
    4394        return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(separator), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
    4395    }
    4396
    4397    /**
    4398     * Joins the elements of the provided {@link List} into a single String
    4399     * containing the provided list of elements.
    4400     *
    4401     * <p>No delimiter is added before or after the list.
    4402     * Null objects or empty strings within the array are represented by
    4403     * empty strings.</p>
    4404     *
    4405     * <pre>
    4406     * StringUtils.join(null, *)               = null
    4407     * StringUtils.join([], *)                 = ""
    4408     * StringUtils.join([null], *)             = ""
    4409     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4410     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4411     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4412     * </pre>
    4413     *
    4414     * @param list  the {@link List} of values to join together, may be null
    4415     * @param separator  the separator character to use
    4416     * @param startIndex the first index to start joining from.  It is
    4417     * an error to pass in a start index past the end of the list
    4418     * @param endIndex the index to stop joining from (exclusive). It is
    4419     * an error to pass in an end index past the end of the list
    4420     * @return the joined String, {@code null} if null list input
    4421     * @since 3.8
    4422     */
    4423    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
    4424        if (list == null) {
    4425            return null;
    4426        }
    4427        final int noOfItems = endIndex - startIndex;
    4428        if (noOfItems <= 0) {
    4429            return EMPTY;
    4430        }
    4431        final List<?> subList = list.subList(startIndex, endIndex);
    4432        return join(subList.iterator(), separator);
    4433    }
    4434
    4435    /**
    4436     * Joins the elements of the provided {@link List} into a single String
    4437     * containing the provided list of elements.
    4438     *
    4439     * <p>No delimiter is added before or after the list.
    4440     * Null objects or empty strings within the array are represented by
    4441     * empty strings.</p>
    4442     *
    4443     * <pre>
    4444     * StringUtils.join(null, *)               = null
    4445     * StringUtils.join([], *)                 = ""
    4446     * StringUtils.join([null], *)             = ""
    4447     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4448     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4449     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4450     * </pre>
    4451     *
    4452     * @param list  the {@link List} of values to join together, may be null
    4453     * @param separator  the separator character to use
    4454     * @param startIndex the first index to start joining from.  It is
    4455     * an error to pass in a start index past the end of the list
    4456     * @param endIndex the index to stop joining from (exclusive). It is
    4457     * an error to pass in an end index past the end of the list
    4458     * @return the joined String, {@code null} if null list input
    4459     * @since 3.8
    4460     */
    4461    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
    4462        if (list == null) {
    4463            return null;
    4464        }
    4465        final int noOfItems = endIndex - startIndex;
    4466        if (noOfItems <= 0) {
    4467            return EMPTY;
    4468        }
    4469        final List<?> subList = list.subList(startIndex, endIndex);
    4470        return join(subList.iterator(), separator);
    4471    }
    4472
    4473
    4474    /**
    4475     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4476     *
    4477     * <p>
    4478     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4479     * by empty strings.
    4480     * </p>
    4481     *
    4482     * <pre>
    4483     * StringUtils.join(null, *)               = null
    4484     * StringUtils.join([], *)                 = ""
    4485     * StringUtils.join([null], *)             = ""
    4486     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4487     * StringUtils.join([1, 2, 3], null) = "123"
    4488     * </pre>
    4489     *
    4490     * @param array
    4491     *            the array of values to join together, may be null
    4492     * @param separator
    4493     *            the separator character to use
    4494     * @return the joined String, {@code null} if null array input
    4495     * @since 3.2
    4496     */
    4497    public static String join(final long[] array, final char separator) {
    4498        if (array == null) {
    4499            return null;
    4500        }
    4501        return join(array, separator, 0, array.length);
    4502    }
    4503
    4504    /**
    4505     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4506     *
    4507     * <p>
    4508     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4509     * by empty strings.
    4510     * </p>
    4511     *
    4512     * <pre>
    4513     * StringUtils.join(null, *)               = null
    4514     * StringUtils.join([], *)                 = ""
    4515     * StringUtils.join([null], *)             = ""
    4516     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4517     * StringUtils.join([1, 2, 3], null) = "123"
    4518     * </pre>
    4519     *
    4520     * @param array
    4521     *            the array of values to join together, may be null
    4522     * @param delimiter
    4523     *            the separator character to use
    4524     * @param startIndex
    4525     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4526     *            array
    4527     * @param endIndex
    4528     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4529     *            the array
    4530     * @return the joined String, {@code null} if null array input
    4531     * @since 3.2
    4532     */
    4533    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
    4534        if (array == null) {
    4535            return null;
    4536        }
    4537        if (endIndex - startIndex <= 0) {
    4538            return EMPTY;
    4539        }
    4540        final StringBuilder stringBuilder = new StringBuilder();
    4541        for (int i = startIndex; i < endIndex; i++) {
    4542            stringBuilder
    4543                    .append(array[i])
    4544                    .append(delimiter);
    4545        }
    4546        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4547    }
    4548
    4549    /**
    4550     * Joins the elements of the provided array into a single String
    4551     * containing the provided list of elements.
    4552     *
    4553     * <p>No delimiter is added before or after the list.
    4554     * Null objects or empty strings within the array are represented by
    4555     * empty strings.</p>
    4556     *
    4557     * <pre>
    4558     * StringUtils.join(null, *)               = null
    4559     * StringUtils.join([], *)                 = ""
    4560     * StringUtils.join([null], *)             = ""
    4561     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4562     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4563     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4564     * </pre>
    4565     *
    4566     * @param array  the array of values to join together, may be null
    4567     * @param delimiter  the separator character to use
    4568     * @return the joined String, {@code null} if null array input
    4569     * @since 2.0
    4570     */
    4571    public static String join(final Object[] array, final char delimiter) {
    4572        if (array == null) {
    4573            return null;
    4574        }
    4575        return join(array, delimiter, 0, array.length);
    4576    }
    4577
    4578    /**
    4579     * Joins the elements of the provided array into a single String
    4580     * containing the provided list of elements.
    4581     *
    4582     * <p>No delimiter is added before or after the list.
    4583     * Null objects or empty strings within the array are represented by
    4584     * empty strings.</p>
    4585     *
    4586     * <pre>
    4587     * StringUtils.join(null, *)               = null
    4588     * StringUtils.join([], *)                 = ""
    4589     * StringUtils.join([null], *)             = ""
    4590     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4591     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4592     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4593     * </pre>
    4594     *
    4595     * @param array  the array of values to join together, may be null
    4596     * @param delimiter  the separator character to use
    4597     * @param startIndex the first index to start joining from.  It is
    4598     * an error to pass in a start index past the end of the array
    4599     * @param endIndex the index to stop joining from (exclusive). It is
    4600     * an error to pass in an end index past the end of the array
    4601     * @return the joined String, {@code null} if null array input
    4602     * @since 2.0
    4603     */
    4604    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
    4605        return join(array, String.valueOf(delimiter), startIndex, endIndex);
    4606    }
    4607
    4608    /**
    4609     * Joins the elements of the provided array into a single String
    4610     * containing the provided list of elements.
    4611     *
    4612     * <p>No delimiter is added before or after the list.
    4613     * A {@code null} separator is the same as an empty String ("").
    4614     * Null objects or empty strings within the array are represented by
    4615     * empty strings.</p>
    4616     *
    4617     * <pre>
    4618     * StringUtils.join(null, *)                = null
    4619     * StringUtils.join([], *)                  = ""
    4620     * StringUtils.join([null], *)              = ""
    4621     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    4622     * StringUtils.join(["a", "b", "c"], null)  = "abc"
    4623     * StringUtils.join(["a", "b", "c"], "")    = "abc"
    4624     * StringUtils.join([null, "", "a"], ',')   = ",,a"
    4625     * </pre>
    4626     *
    4627     * @param array  the array of values to join together, may be null
    4628     * @param delimiter  the separator character to use, null treated as ""
    4629     * @return the joined String, {@code null} if null array input
    4630     */
    4631    public static String join(final Object[] array, final String delimiter) {
    4632        return array != null ? join(array, toStringOrEmpty(delimiter), 0, array.length) : null;
    4633    }
    4634
    4635    /**
    4636     * Joins the elements of the provided array into a single String
    4637     * containing the provided list of elements.
    4638     *
    4639     * <p>No delimiter is added before or after the list.
    4640     * A {@code null} separator is the same as an empty String ("").
    4641     * Null objects or empty strings within the array are represented by
    4642     * empty strings.</p>
    4643     *
    4644     * <pre>
    4645     * StringUtils.join(null, *, *, *)                = null
    4646     * StringUtils.join([], *, *, *)                  = ""
    4647     * StringUtils.join([null], *, *, *)              = ""
    4648     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
    4649     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
    4650     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
    4651     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
    4652     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
    4653     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
    4654     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
    4655     * </pre>
    4656     *
    4657     * @param array  the array of values to join together, may be null
    4658     * @param delimiter  the separator character to use, null treated as ""
    4659     * @param startIndex the first index to start joining from.
    4660     * @param endIndex the index to stop joining from (exclusive).
    4661     * @return the joined String, {@code null} if null array input; or the empty string
    4662     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
    4663     * {@code endIndex - startIndex}
    4664     * @throws ArrayIndexOutOfBoundsException ife<br>
    4665     * {@code startIndex < 0} or <br>
    4666     * {@code startIndex >= array.length()} or <br>
    4667     * {@code endIndex < 0} or <br>
    4668     * {@code endIndex > array.length()}
    4669     */
    4670    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
    4671        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
    4672            .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, StringUtils::toStringOrEmpty)) : null;
    4673    }
    4674
    4675    /**
    4676     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4677     *
    4678     * <p>
    4679     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4680     * by empty strings.
    4681     * </p>
    4682     *
    4683     * <pre>
    4684     * StringUtils.join(null, *)               = null
    4685     * StringUtils.join([], *)                 = ""
    4686     * StringUtils.join([null], *)             = ""
    4687     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4688     * StringUtils.join([1, 2, 3], null) = "123"
    4689     * </pre>
    4690     *
    4691     * @param array
    4692     *            the array of values to join together, may be null
    4693     * @param delimiter
    4694     *            the separator character to use
    4695     * @return the joined String, {@code null} if null array input
    4696     * @since 3.2
    4697     */
    4698    public static String join(final short[] array, final char delimiter) {
    4699        if (array == null) {
    4700            return null;
    4701        }
    4702        return join(array, delimiter, 0, array.length);
    4703    }
    4704
    4705    /**
    4706     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4707     *
    4708     * <p>
    4709     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4710     * by empty strings.
    4711     * </p>
    4712     *
    4713     * <pre>
    4714     * StringUtils.join(null, *)               = null
    4715     * StringUtils.join([], *)                 = ""
    4716     * StringUtils.join([null], *)             = ""
    4717     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4718     * StringUtils.join([1, 2, 3], null) = "123"
    4719     * </pre>
    4720     *
    4721     * @param array
    4722     *            the array of values to join together, may be null
    4723     * @param delimiter
    4724     *            the separator character to use
    4725     * @param startIndex
    4726     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4727     *            array
    4728     * @param endIndex
    4729     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4730     *            the array
    4731     * @return the joined String, {@code null} if null array input
    4732     * @since 3.2
    4733     */
    4734    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
    4735        if (array == null) {
    4736            return null;
    4737        }
    4738        if (endIndex - startIndex <= 0) {
    4739            return EMPTY;
    4740        }
    4741        final StringBuilder stringBuilder = new StringBuilder();
    4742        for (int i = startIndex; i < endIndex; i++) {
    4743            stringBuilder
    4744                    .append(array[i])
    4745                    .append(delimiter);
    4746        }
    4747        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4748    }
    4749
    4750    /**
    4751     * Joins the elements of the provided array into a single String
    4752     * containing the provided list of elements.
    4753     *
    4754     * <p>No separator is added to the joined String.
    4755     * Null objects or empty strings within the array are represented by
    4756     * empty strings.</p>
    4757     *
    4758     * <pre>
    4759     * StringUtils.join(null)            = null
    4760     * StringUtils.join([])              = ""
    4761     * StringUtils.join([null])          = ""
    4762     * StringUtils.join(["a", "b", "c"]) = "abc"
    4763     * StringUtils.join([null, "", "a"]) = "a"
    4764     * </pre>
    4765     *
    4766     * @param <T> the specific type of values to join together
    4767     * @param elements  the values to join together, may be null
    4768     * @return the joined String, {@code null} if null array input
    4769     * @since 2.0
    4770     * @since 3.0 Changed signature to use varargs
    4771     */
    4772    @SafeVarargs
    4773    public static <T> String join(final T... elements) {
    4774        return join(elements, null);
    4775    }
    4776
    4777    /**
    4778     * Joins the elements of the provided varargs into a
    4779     * single String containing the provided elements.
    4780     *
    4781     * <p>No delimiter is added before or after the list.
    4782     * {@code null} elements and separator are treated as empty Strings ("").</p>
    4783     *
    4784     * <pre>
    4785     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
    4786     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
    4787     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
    4788     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
    4789     * </pre>
    4790     *
    4791     * @param delimiter the separator character to use, null treated as ""
    4792     * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
    4793     * @return the joined String.
    4794     * @throws IllegalArgumentException if a null varargs is provided
    4795     * @since 3.5
    4796     */
    4797    public static String joinWith(final String delimiter, final Object... array) {
    4798        if (array == null) {
    4799            throw new IllegalArgumentException("Object varargs must not be null");
    4800        }
    4801        return join(array, delimiter);
    4802    }
    4803
    4804    /**
    4805     * Finds the last index within a CharSequence, handling {@code null}.
    4806     * This method uses {@link String#lastIndexOf(String)} if possible.
    4807     *
    4808     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    4809     *
    4810     * <pre>
    4811     * StringUtils.lastIndexOf(null, *)          = -1
    4812     * StringUtils.lastIndexOf(*, null)          = -1
    4813     * StringUtils.lastIndexOf("", "")           = 0
    4814     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    4815     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    4816     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    4817     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    4818     * </pre>
    4819     *
    4820     * @param seq  the CharSequence to check, may be null
    4821     * @param searchSeq  the CharSequence to find, may be null
    4822     * @return the last index of the search String,
    4823     *  -1 if no match or {@code null} string input
    4824     * @since 2.0
    4825     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
    4826     */
    4827    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
    4828        if (seq == null) {
    4829            return INDEX_NOT_FOUND;
    4830        }
    4831        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
    4832    }
    4833
    4834    /**
    4835     * Finds the last index within a CharSequence, handling {@code null}.
    4836     * This method uses {@link String#lastIndexOf(String, int)} if possible.
    4837     *
    4838     * <p>A {@code null} CharSequence will return {@code -1}.
    4839     * A negative start position returns {@code -1}.
    4840     * An empty ("") search CharSequence always matches unless the start position is negative.
    4841     * A start position greater than the string length searches the whole string.
    4842     * The search starts at the startPos and works backwards; matches starting after the start
    4843     * position are ignored.
    4844     * </p>
    4845     *
    4846     * <pre>
    4847     * StringUtils.lastIndexOf(null, *, *)          = -1
    4848     * StringUtils.lastIndexOf(*, null, *)          = -1
    4849     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    4850     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    4851     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    4852     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    4853     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    4854     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    4855     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    4856     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
    4857     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
    4858     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
    4859     * </pre>
    4860     *
    4861     * @param seq  the CharSequence to check, may be null
    4862     * @param searchSeq  the CharSequence to find, may be null
    4863     * @param startPos  the start position, negative treated as zero
    4864     * @return the last index of the search CharSequence (always &le; startPos),
    4865     *  -1 if no match or {@code null} string input
    4866     * @since 2.0
    4867     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
    4868     */
    4869    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    4870        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
    4871    }
    4872
    4873    /**
    4874     * Returns the index within {@code seq} of the last occurrence of
    4875     * the specified character. For values of {@code searchChar} in the
    4876     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
    4877     * units) returned is the largest value <i>k</i> such that:
    4878     * <blockquote><pre>
    4879     * this.charAt(<i>k</i>) == searchChar
    4880     * </pre></blockquote>
    4881     * is true. For other values of {@code searchChar}, it is the
    4882     * largest value <i>k</i> such that:
    4883     * <blockquote><pre>
    4884     * this.codePointAt(<i>k</i>) == searchChar
    4885     * </pre></blockquote>
    4886     * is true.  In either case, if no such character occurs in this
    4887     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4888     * {@link CharSequence} will return {@code -1}. The
    4889     * {@code seq} {@link CharSequence} object is searched backwards
    4890     * starting at the last character.
    4891     *
    4892     * <pre>
    4893     * StringUtils.lastIndexOf(null, *)         = -1
    4894     * StringUtils.lastIndexOf("", *)           = -1
    4895     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    4896     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    4897     * </pre>
    4898     *
    4899     * @param seq  the {@link CharSequence} to check, may be null
    4900     * @param searchChar  the character to find
    4901     * @return the last index of the search character,
    4902     *  -1 if no match or {@code null} string input
    4903     * @since 2.0
    4904     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
    4905     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    4906     */
    4907    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
    4908        if (isEmpty(seq)) {
    4909            return INDEX_NOT_FOUND;
    4910        }
    4911        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
    4912    }
    4913
    4914    /**
    4915     * Returns the index within {@code seq} of the last occurrence of
    4916     * the specified character, searching backward starting at the
    4917     * specified index. For values of {@code searchChar} in the range
    4918     * from 0 to 0xFFFF (inclusive), the index returned is the largest
    4919     * value <i>k</i> such that:
    4920     * <blockquote><pre>
    4921     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    4922     * </pre></blockquote>
    4923     * is true. For other values of {@code searchChar}, it is the
    4924     * largest value <i>k</i> such that:
    4925     * <blockquote><pre>
    4926     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    4927     * </pre></blockquote>
    4928     * is true. In either case, if no such character occurs in {@code seq}
    4929     * at or before position {@code startPos}, then
    4930     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4931     * {@link CharSequence} will return {@code -1}. A start position greater
    4932     * than the string length searches the whole string.
    4933     * The search starts at the {@code startPos} and works backwards;
    4934     * matches starting after the start position are ignored.
    4935     *
    4936     * <p>All indices are specified in {@code char} values
    4937     * (Unicode code units).
    4938     *
    4939     * <pre>
    4940     * StringUtils.lastIndexOf(null, *, *)          = -1
    4941     * StringUtils.lastIndexOf("", *,  *)           = -1
    4942     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    4943     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    4944     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    4945     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    4946     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    4947     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    4948     * </pre>
    4949     *
    4950     * @param seq  the CharSequence to check, may be null
    4951     * @param searchChar  the character to find
    4952     * @param startPos  the start position
    4953     * @return the last index of the search character (always &le; startPos),
    4954     *  -1 if no match or {@code null} string input
    4955     * @since 2.0
    4956     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
    4957     */
    4958    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
    4959        if (isEmpty(seq)) {
    4960            return INDEX_NOT_FOUND;
    4961        }
    4962        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
    4963    }
    4964
    4965    /**
    4966     * Find the latest index of any substring in a set of potential substrings.
    4967     *
    4968     * <p>A {@code null} CharSequence will return {@code -1}.
    4969     * A {@code null} search array will return {@code -1}.
    4970     * A {@code null} or zero length search array entry will be ignored,
    4971     * but a search array containing "" will return the length of {@code str}
    4972     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
    4973     *
    4974     * <pre>
    4975     * StringUtils.lastIndexOfAny(null, *)                    = -1
    4976     * StringUtils.lastIndexOfAny(*, null)                    = -1
    4977     * StringUtils.lastIndexOfAny(*, [])                      = -1
    4978     * StringUtils.lastIndexOfAny(*, [null])                  = -1
    4979     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
    4980     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
    4981     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    4982     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    4983     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
    4984     * </pre>
    4985     *
    4986     * @param str  the CharSequence to check, may be null
    4987     * @param searchStrs  the CharSequences to search for, may be null
    4988     * @return the last index of any of the CharSequences, -1 if no match
    4989     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
    4990     */
    4991    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    4992        if (str == null || searchStrs == null) {
    4993            return INDEX_NOT_FOUND;
    4994        }
    4995        int ret = INDEX_NOT_FOUND;
    4996        int tmp;
    4997        for (final CharSequence search : searchStrs) {
    4998            if (search == null) {
    4999                continue;
    5000            }
    5001            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
    5002            if (tmp > ret) {
    5003                ret = tmp;
    5004            }
    5005        }
    5006        return ret;
    5007    }
    5008
    5009    /**
    5010     * Case in-sensitive find of the last index within a CharSequence.
    5011     *
    5012     * <p>A {@code null} CharSequence will return {@code -1}.
    5013     * A negative start position returns {@code -1}.
    5014     * An empty ("") search CharSequence always matches unless the start position is negative.
    5015     * A start position greater than the string length searches the whole string.</p>
    5016     *
    5017     * <pre>
    5018     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    5019     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    5020     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    5021     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    5022     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    5023     * </pre>
    5024     *
    5025     * @param str  the CharSequence to check, may be null
    5026     * @param searchStr  the CharSequence to find, may be null
    5027     * @return the first index of the search CharSequence,
    5028     *  -1 if no match or {@code null} string input
    5029     * @since 2.5
    5030     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
    5031     */
    5032    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    5033        if (str == null || searchStr == null) {
    5034            return INDEX_NOT_FOUND;
    5035        }
    5036        return lastIndexOfIgnoreCase(str, searchStr, str.length());
    5037    }
    5038
    5039    /**
    5040     * Case in-sensitive find of the last index within a CharSequence
    5041     * from the specified position.
    5042     *
    5043     * <p>A {@code null} CharSequence will return {@code -1}.
    5044     * A negative start position returns {@code -1}.
    5045     * An empty ("") search CharSequence always matches unless the start position is negative.
    5046     * A start position greater than the string length searches the whole string.
    5047     * The search starts at the startPos and works backwards; matches starting after the start
    5048     * position are ignored.
    5049     * </p>
    5050     *
    5051     * <pre>
    5052     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    5053     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    5054     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    5055     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    5056     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    5057     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    5058     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    5059     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    5060     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    5061     * </pre>
    5062     *
    5063     * @param str  the CharSequence to check, may be null
    5064     * @param searchStr  the CharSequence to find, may be null
    5065     * @param startPos  the start position
    5066     * @return the last index of the search CharSequence (always &le; startPos),
    5067     *  -1 if no match or {@code null} input
    5068     * @since 2.5
    5069     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
    5070     */
    5071    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    5072        if (str == null || searchStr == null) {
    5073            return INDEX_NOT_FOUND;
    5074        }
    5075        final int searchStrLength = searchStr.length();
    5076        final int strLength = str.length();
    5077        if (startPos > strLength - searchStrLength) {
    5078            startPos = strLength - searchStrLength;
    5079        }
    5080        if (startPos < 0) {
    5081            return INDEX_NOT_FOUND;
    5082        }
    5083        if (searchStrLength == 0) {
    5084            return startPos;
    5085        }
    5086
    5087        for (int i = startPos; i >= 0; i--) {
    5088            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) {
    5089                return i;
    5090            }
    5091        }
    5092        return INDEX_NOT_FOUND;
    5093    }
    5094
    5095    /**
    5096     * Finds the n-th last index within a String, handling {@code null}.
    5097     * This method uses {@link String#lastIndexOf(String)}.
    5098     *
    5099     * <p>A {@code null} String will return {@code -1}.</p>
    5100     *
    5101     * <pre>
    5102     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    5103     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    5104     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    5105     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    5106     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    5107     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    5108     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    5109     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    5110     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    5111     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    5112     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    5113     * </pre>
    5114     *
    5115     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
    5116     *
    5117     * <pre>
    5118     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    5119     * </pre>
    5120     *
    5121     * @param str  the CharSequence to check, may be null
    5122     * @param searchStr  the CharSequence to find, may be null
    5123     * @param ordinal  the n-th last {@code searchStr} to find
    5124     * @return the n-th last index of the search CharSequence,
    5125     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5126     * @since 2.5
    5127     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
    5128     */
    5129    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5130        return ordinalIndexOf(str, searchStr, ordinal, true);
    5131    }
    5132
    5133    /**
    5134     * Gets the leftmost {@code len} characters of a String.
    5135     *
    5136     * <p>If {@code len} characters are not available, or the
    5137     * String is {@code null}, the String will be returned without
    5138     * an exception. An empty String is returned if len is negative.</p>
    5139     *
    5140     * <pre>
    5141     * StringUtils.left(null, *)    = null
    5142     * StringUtils.left(*, -ve)     = ""
    5143     * StringUtils.left("", *)      = ""
    5144     * StringUtils.left("abc", 0)   = ""
    5145     * StringUtils.left("abc", 2)   = "ab"
    5146     * StringUtils.left("abc", 4)   = "abc"
    5147     * </pre>
    5148     *
    5149     * @param str  the String to get the leftmost characters from, may be null
    5150     * @param len  the length of the required String
    5151     * @return the leftmost characters, {@code null} if null String input
    5152     */
    5153    public static String left(final String str, final int len) {
    5154        if (str == null) {
    5155            return null;
    5156        }
    5157        if (len < 0) {
    5158            return EMPTY;
    5159        }
    5160        if (str.length() <= len) {
    5161            return str;
    5162        }
    5163        return str.substring(0, len);
    5164    }
    5165
    5166    /**
    5167     * Left pad a String with spaces (' ').
    5168     *
    5169     * <p>The String is padded to the size of {@code size}.</p>
    5170     *
    5171     * <pre>
    5172     * StringUtils.leftPad(null, *)   = null
    5173     * StringUtils.leftPad("", 3)     = "   "
    5174     * StringUtils.leftPad("bat", 3)  = "bat"
    5175     * StringUtils.leftPad("bat", 5)  = "  bat"
    5176     * StringUtils.leftPad("bat", 1)  = "bat"
    5177     * StringUtils.leftPad("bat", -1) = "bat"
    5178     * </pre>
    5179     *
    5180     * @param str  the String to pad out, may be null
    5181     * @param size  the size to pad to
    5182     * @return left padded String or original String if no padding is necessary,
    5183     *  {@code null} if null String input
    5184     */
    5185    public static String leftPad(final String str, final int size) {
    5186        return leftPad(str, size, ' ');
    5187    }
    5188
    5189    /**
    5190     * Left pad a String with a specified character.
    5191     *
    5192     * <p>Pad to a size of {@code size}.</p>
    5193     *
    5194     * <pre>
    5195     * StringUtils.leftPad(null, *, *)     = null
    5196     * StringUtils.leftPad("", 3, 'z')     = "zzz"
    5197     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    5198     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    5199     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    5200     * StringUtils.leftPad("bat", -1, 'z') = "bat"
    5201     * </pre>
    5202     *
    5203     * @param str  the String to pad out, may be null
    5204     * @param size  the size to pad to
    5205     * @param padChar  the character to pad with
    5206     * @return left padded String or original String if no padding is necessary,
    5207     *  {@code null} if null String input
    5208     * @since 2.0
    5209     */
    5210    public static String leftPad(final String str, final int size, final char padChar) {
    5211        if (str == null) {
    5212            return null;
    5213        }
    5214        final int pads = size - str.length();
    5215        if (pads <= 0) {
    5216            return str; // returns original String when possible
    5217        }
    5218        if (pads > PAD_LIMIT) {
    5219            return leftPad(str, size, String.valueOf(padChar));
    5220        }
    5221        return repeat(padChar, pads).concat(str);
    5222    }
    5223
    5224    /**
    5225     * Left pad a String with a specified String.
    5226     *
    5227     * <p>Pad to a size of {@code size}.</p>
    5228     *
    5229     * <pre>
    5230     * StringUtils.leftPad(null, *, *)      = null
    5231     * StringUtils.leftPad("", 3, "z")      = "zzz"
    5232     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    5233     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    5234     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    5235     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    5236     * StringUtils.leftPad("bat", -1, "yz") = "bat"
    5237     * StringUtils.leftPad("bat", 5, null)  = "  bat"
    5238     * StringUtils.leftPad("bat", 5, "")    = "  bat"
    5239     * </pre>
    5240     *
    5241     * @param str  the String to pad out, may be null
    5242     * @param size  the size to pad to
    5243     * @param padStr  the String to pad with, null or empty treated as single space
    5244     * @return left padded String or original String if no padding is necessary,
    5245     *  {@code null} if null String input
    5246     */
    5247    public static String leftPad(final String str, final int size, String padStr) {
    5248        if (str == null) {
    5249            return null;
    5250        }
    5251        if (isEmpty(padStr)) {
    5252            padStr = SPACE;
    5253        }
    5254        final int padLen = padStr.length();
    5255        final int strLen = str.length();
    5256        final int pads = size - strLen;
    5257        if (pads <= 0) {
    5258            return str; // returns original String when possible
    5259        }
    5260        if (padLen == 1 && pads <= PAD_LIMIT) {
    5261            return leftPad(str, size, padStr.charAt(0));
    5262        }
    5263
    5264        if (pads == padLen) {
    5265            return padStr.concat(str);
    5266        }
    5267        if (pads < padLen) {
    5268            return padStr.substring(0, pads).concat(str);
    5269        }
    5270        final char[] padding = new char[pads];
    5271        final char[] padChars = padStr.toCharArray();
    5272        for (int i = 0; i < pads; i++) {
    5273            padding[i] = padChars[i % padLen];
    5274        }
    5275        return new String(padding).concat(str);
    5276    }
    5277
    5278    /**
    5279     * Gets a CharSequence length or {@code 0} if the CharSequence is
    5280     * {@code null}.
    5281     *
    5282     * @param cs
    5283     *            a CharSequence or {@code null}
    5284     * @return CharSequence length or {@code 0} if the CharSequence is
    5285     *         {@code null}.
    5286     * @since 2.4
    5287     * @since 3.0 Changed signature from length(String) to length(CharSequence)
    5288     */
    5289    public static int length(final CharSequence cs) {
    5290        return cs == null ? 0 : cs.length();
    5291    }
    5292
    5293    /**
    5294     * Converts a String to lower case as per {@link String#toLowerCase()}.
    5295     *
    5296     * <p>A {@code null} input String returns {@code null}.</p>
    5297     *
    5298     * <pre>
    5299     * StringUtils.lowerCase(null)  = null
    5300     * StringUtils.lowerCase("")    = ""
    5301     * StringUtils.lowerCase("aBc") = "abc"
    5302     * </pre>
    5303     *
    5304     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
    5305     * the result of this method is affected by the current locale.
    5306     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    5307     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    5308     *
    5309     * @param str  the String to lower case, may be null
    5310     * @return the lower cased String, {@code null} if null String input
    5311     */
    5312    public static String lowerCase(final String str) {
    5313        if (str == null) {
    5314            return null;
    5315        }
    5316        return str.toLowerCase();
    5317    }
    5318
    5319    /**
    5320     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
    5321     *
    5322     * <p>A {@code null} input String returns {@code null}.</p>
    5323     *
    5324     * <pre>
    5325     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    5326     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    5327     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    5328     * </pre>
    5329     *
    5330     * @param str  the String to lower case, may be null
    5331     * @param locale  the locale that defines the case transformation rules, must not be null
    5332     * @return the lower cased String, {@code null} if null String input
    5333     * @since 2.5
    5334     */
    5335    public static String lowerCase(final String str, final Locale locale) {
    5336        if (str == null) {
    5337            return null;
    5338        }
    5339        return str.toLowerCase(LocaleUtils.toLocale(locale));
    5340    }
    5341
    5342    private static int[] matches(final CharSequence first, final CharSequence second) {
    5343        final CharSequence max;
    5344        final CharSequence min;
    5345        if (first.length() > second.length()) {
    5346            max = first;
    5347            min = second;
    5348        } else {
    5349            max = second;
    5350            min = first;
    5351        }
    5352        final int range = Math.max(max.length() / 2 - 1, 0);
    5353        final int[] matchIndexes = new int[min.length()];
    5354        Arrays.fill(matchIndexes, -1);
    5355        final boolean[] matchFlags = new boolean[max.length()];
    5356        int matches = 0;
    5357        for (int mi = 0; mi < min.length(); mi++) {
    5358            final char c1 = min.charAt(mi);
    5359            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
    5360                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
    5361                    matchIndexes[mi] = xi;
    5362                    matchFlags[xi] = true;
    5363                    matches++;
    5364                    break;
    5365                }
    5366            }
    5367        }
    5368        final char[] ms1 = new char[matches];
    5369        final char[] ms2 = new char[matches];
    5370        for (int i = 0, si = 0; i < min.length(); i++) {
    5371            if (matchIndexes[i] != -1) {
    5372                ms1[si] = min.charAt(i);
    5373                si++;
    5374            }
    5375        }
    5376        for (int i = 0, si = 0; i < max.length(); i++) {
    5377            if (matchFlags[i]) {
    5378                ms2[si] = max.charAt(i);
    5379                si++;
    5380            }
    5381        }
    5382        int transpositions = 0;
    5383        for (int mi = 0; mi < ms1.length; mi++) {
    5384            if (ms1[mi] != ms2[mi]) {
    5385                transpositions++;
    5386            }
    5387        }
    5388        int prefix = 0;
    5389        for (int mi = 0; mi < min.length(); mi++) {
    5390            if (first.charAt(mi) != second.charAt(mi)) {
    5391                break;
    5392            }
    5393            prefix++;
    5394        }
    5395        return new int[] { matches, transpositions / 2, prefix, max.length() };
    5396    }
    5397
    5398    /**
    5399     * Gets {@code len} characters from the middle of a String.
    5400     *
    5401     * <p>If {@code len} characters are not available, the remainder
    5402     * of the String will be returned without an exception. If the
    5403     * String is {@code null}, {@code null} will be returned.
    5404     * An empty String is returned if len is negative or exceeds the
    5405     * length of {@code str}.</p>
    5406     *
    5407     * <pre>
    5408     * StringUtils.mid(null, *, *)    = null
    5409     * StringUtils.mid(*, *, -ve)     = ""
    5410     * StringUtils.mid("", 0, *)      = ""
    5411     * StringUtils.mid("abc", 0, 2)   = "ab"
    5412     * StringUtils.mid("abc", 0, 4)   = "abc"
    5413     * StringUtils.mid("abc", 2, 4)   = "c"
    5414     * StringUtils.mid("abc", 4, 2)   = ""
    5415     * StringUtils.mid("abc", -2, 2)  = "ab"
    5416     * </pre>
    5417     *
    5418     * @param str  the String to get the characters from, may be null
    5419     * @param pos  the position to start from, negative treated as zero
    5420     * @param len  the length of the required String
    5421     * @return the middle characters, {@code null} if null String input
    5422     */
    5423    public static String mid(final String str, int pos, final int len) {
    5424        if (str == null) {
    5425            return null;
    5426        }
    5427        if (len < 0 || pos > str.length()) {
    5428            return EMPTY;
    5429        }
    5430        if (pos < 0) {
    5431            pos = 0;
    5432        }
    5433        if (str.length() <= pos + len) {
    5434            return str.substring(pos);
    5435        }
    5436        return str.substring(pos, pos + len);
    5437    }
    5438
    5439    /**
    5440     * Similar to <a
    5441     * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
    5442     * -space</a>
    5443     *
    5444     * <p>
    5445     * The function returns the argument string with whitespace normalized by using
    5446     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
    5447     * and then replacing sequences of whitespace characters by a single space.
    5448     * </p>
    5449     * In XML Whitespace characters are the same as those allowed by the <a
    5450     * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
    5451     * <p>
    5452     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
    5453     *
    5454     * <p>For reference:</p>
    5455     * <ul>
    5456     * <li>\x0B = vertical tab</li>
    5457     * <li>\f = #xC = form feed</li>
    5458     * <li>#x20 = space</li>
    5459     * <li>#x9 = \t</li>
    5460     * <li>#xA = \n</li>
    5461     * <li>#xD = \r</li>
    5462     * </ul>
    5463     *
    5464     * <p>
    5465     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
    5466     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
    5467     * ends of this String.
    5468     * </p>
    5469     *
    5470     * @see Pattern
    5471     * @see #trim(String)
    5472     * @see <a
    5473     *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
    5474     * @param str the source String to normalize whitespaces from, may be null
    5475     * @return the modified string with whitespace normalized, {@code null} if null String input
    5476     *
    5477     * @since 3.0
    5478     */
    5479    public static String normalizeSpace(final String str) {
    5480        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
    5481        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
    5482        if (isEmpty(str)) {
    5483            return str;
    5484        }
    5485        final int size = str.length();
    5486        final char[] newChars = new char[size];
    5487        int count = 0;
    5488        int whitespacesCount = 0;
    5489        boolean startWhitespaces = true;
    5490        for (int i = 0; i < size; i++) {
    5491            final char actualChar = str.charAt(i);
    5492            final boolean isWhitespace = Character.isWhitespace(actualChar);
    5493            if (isWhitespace) {
    5494                if (whitespacesCount == 0 && !startWhitespaces) {
    5495                    newChars[count++] = SPACE.charAt(0);
    5496                }
    5497                whitespacesCount++;
    5498            } else {
    5499                startWhitespaces = false;
    5500                newChars[count++] = actualChar == 160 ? 32 : actualChar;
    5501                whitespacesCount = 0;
    5502            }
    5503        }
    5504        if (startWhitespaces) {
    5505            return EMPTY;
    5506        }
    5507        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
    5508    }
    5509
    5510    /**
    5511     * Finds the n-th index within a CharSequence, handling {@code null}.
    5512     * This method uses {@link String#indexOf(String)} if possible.
    5513     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
    5514     * incrementing the starting index by one after each successful match
    5515     * (unless {@code searchStr} is an empty string in which case the position
    5516     * is never incremented and {@code 0} is returned immediately).
    5517     * This means that matches may overlap.</p>
    5518     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5519     *
    5520     * <pre>
    5521     * StringUtils.ordinalIndexOf(null, *, *)          = -1
    5522     * StringUtils.ordinalIndexOf(*, null, *)          = -1
    5523     * StringUtils.ordinalIndexOf("", "", *)           = 0
    5524     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    5525     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    5526     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    5527     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    5528     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    5529     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    5530     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    5531     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    5532     * </pre>
    5533     *
    5534     * <p>Matches may overlap:</p>
    5535     * <pre>
    5536     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
    5537     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
    5538     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
    5539     *
    5540     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
    5541     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
    5542     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
    5543     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
    5544     * </pre>
    5545     *
    5546     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
    5547     *
    5548     * <pre>
    5549     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    5550     * </pre>
    5551     *
    5552     * @param str  the CharSequence to check, may be null
    5553     * @param searchStr  the CharSequence to find, may be null
    5554     * @param ordinal  the n-th {@code searchStr} to find
    5555     * @return the n-th index of the search CharSequence,
    5556     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5557     * @since 2.1
    5558     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
    5559     */
    5560    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5561        return ordinalIndexOf(str, searchStr, ordinal, false);
    5562    }
    5563
    5564    /**
    5565     * Finds the n-th index within a String, handling {@code null}.
    5566     * This method uses {@link String#indexOf(String)} if possible.
    5567     * <p>Note that matches may overlap<p>
    5568     *
    5569     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5570     *
    5571     * @param str  the CharSequence to check, may be null
    5572     * @param searchStr  the CharSequence to find, may be null
    5573     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
    5574     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
    5575     * @return the n-th index of the search CharSequence,
    5576     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5577     */
    5578    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
    5579    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
    5580        if (str == null || searchStr == null || ordinal <= 0) {
    5581            return INDEX_NOT_FOUND;
    5582        }
    5583        if (searchStr.length() == 0) {
    5584            return lastIndex ? str.length() : 0;
    5585        }
    5586        int found = 0;
    5587        // set the initial index beyond the end of the string
    5588        // this is to allow for the initial index decrement/increment
    5589        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    5590        do {
    5591            if (lastIndex) {
    5592                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
    5593            } else {
    5594                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
    5595            }
    5596            if (index < 0) {
    5597                return index;
    5598            }
    5599            found++;
    5600        } while (found < ordinal);
    5601        return index;
    5602    }
    5603
    5604    /**
    5605     * Overlays part of a String with another String.
    5606     *
    5607     * <p>A {@code null} string input returns {@code null}.
    5608     * A negative index is treated as zero.
    5609     * An index greater than the string length is treated as the string length.
    5610     * The start index is always the smaller of the two indices.</p>
    5611     *
    5612     * <pre>
    5613     * StringUtils.overlay(null, *, *, *)            = null
    5614     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    5615     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    5616     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    5617     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    5618     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    5619     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    5620     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    5621     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    5622     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    5623     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    5624     * </pre>
    5625     *
    5626     * @param str  the String to do overlaying in, may be null
    5627     * @param overlay  the String to overlay, may be null
    5628     * @param start  the position to start overlaying at
    5629     * @param end  the position to stop overlaying before
    5630     * @return overlayed String, {@code null} if null String input
    5631     * @since 2.0
    5632     */
    5633    public static String overlay(final String str, String overlay, int start, int end) {
    5634        if (str == null) {
    5635            return null;
    5636        }
    5637        if (overlay == null) {
    5638            overlay = EMPTY;
    5639        }
    5640        final int len = str.length();
    5641        if (start < 0) {
    5642            start = 0;
    5643        }
    5644        if (start > len) {
    5645            start = len;
    5646        }
    5647        if (end < 0) {
    5648            end = 0;
    5649        }
    5650        if (end > len) {
    5651            end = len;
    5652        }
    5653        if (start > end) {
    5654            final int temp = start;
    5655            start = end;
    5656            end = temp;
    5657        }
    5658        return str.substring(0, start) +
    5659            overlay +
    5660            str.substring(end);
    5661    }
    5662
    5663    /**
    5664     * Prepends the prefix to the start of the string if the string does not
    5665     * already start with any of the prefixes.
    5666     *
    5667     * @param str The string.
    5668     * @param prefix The prefix to prepend to the start of the string.
    5669     * @param ignoreCase Indicates whether the compare should ignore case.
    5670     * @param prefixes Additional prefixes that are valid (optional).
    5671     *
    5672     * @return A new String if prefix was prepended, the same string otherwise.
    5673     */
    5674    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
    5675        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
    5676            return str;
    5677        }
    5678        if (ArrayUtils.isNotEmpty(prefixes)) {
    5679            for (final CharSequence p : prefixes) {
    5680                if (startsWith(str, p, ignoreCase)) {
    5681                    return str;
    5682                }
    5683            }
    5684        }
    5685        return prefix.toString() + str;
    5686    }
    5687
    5688    /**
    5689     * Prepends the prefix to the start of the string if the string does not
    5690     * already start with any of the prefixes.
    5691     *
    5692     * <pre>
    5693     * StringUtils.prependIfMissing(null, null) = null
    5694     * StringUtils.prependIfMissing("abc", null) = "abc"
    5695     * StringUtils.prependIfMissing("", "xyz") = "xyz"
    5696     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
    5697     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
    5698     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
    5699     * </pre>
    5700     * <p>With additional prefixes,</p>
    5701     * <pre>
    5702     * StringUtils.prependIfMissing(null, null, null) = null
    5703     * StringUtils.prependIfMissing("abc", null, null) = "abc"
    5704     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
    5705     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5706     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
    5707     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
    5708     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
    5709     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
    5710     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
    5711     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
    5712     * </pre>
    5713     *
    5714     * @param str The string.
    5715     * @param prefix The prefix to prepend to the start of the string.
    5716     * @param prefixes Additional prefixes that are valid.
    5717     *
    5718     * @return A new String if prefix was prepended, the same string otherwise.
    5719     *
    5720     * @since 3.2
    5721     */
    5722    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5723        return prependIfMissing(str, prefix, false, prefixes);
    5724    }
    5725
    5726    /**
    5727     * Prepends the prefix to the start of the string if the string does not
    5728     * already start, case-insensitive, with any of the prefixes.
    5729     *
    5730     * <pre>
    5731     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
    5732     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
    5733     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
    5734     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
    5735     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
    5736     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
    5737     * </pre>
    5738     * <p>With additional prefixes,</p>
    5739     * <pre>
    5740     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
    5741     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
    5742     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
    5743     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5744     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    5745     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
    5746     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
    5747     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
    5748     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
    5749     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
    5750     * </pre>
    5751     *
    5752     * @param str The string.
    5753     * @param prefix The prefix to prepend to the start of the string.
    5754     * @param prefixes Additional prefixes that are valid (optional).
    5755     *
    5756     * @return A new String if prefix was prepended, the same string otherwise.
    5757     *
    5758     * @since 3.2
    5759     */
    5760    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5761        return prependIfMissing(str, prefix, true, prefixes);
    5762    }
    5763
    5764    /**
    5765     * Removes all occurrences of a character from within the source string.
    5766     *
    5767     * <p>A {@code null} source string will return {@code null}.
    5768     * An empty ("") source string will return the empty string.</p>
    5769     *
    5770     * <pre>
    5771     * StringUtils.remove(null, *)       = null
    5772     * StringUtils.remove("", *)         = ""
    5773     * StringUtils.remove("queued", 'u') = "qeed"
    5774     * StringUtils.remove("queued", 'z') = "queued"
    5775     * </pre>
    5776     *
    5777     * @param str  the source String to search, may be null
    5778     * @param remove  the char to search for and remove, may be null
    5779     * @return the substring with the char removed if found,
    5780     *  {@code null} if null String input
    5781     * @since 2.1
    5782     */
    5783    public static String remove(final String str, final char remove) {
    5784        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    5785            return str;
    5786        }
    5787        final char[] chars = str.toCharArray();
    5788        int pos = 0;
    5789        for (int i = 0; i < chars.length; i++) {
    5790            if (chars[i] != remove) {
    5791                chars[pos++] = chars[i];
    5792            }
    5793        }
    5794        return new String(chars, 0, pos);
    5795    }
    5796
    5797    /**
    5798     * Removes all occurrences of a substring from within the source string.
    5799     *
    5800     * <p>A {@code null} source string will return {@code null}.
    5801     * An empty ("") source string will return the empty string.
    5802     * A {@code null} remove string will return the source string.
    5803     * An empty ("") remove string will return the source string.</p>
    5804     *
    5805     * <pre>
    5806     * StringUtils.remove(null, *)        = null
    5807     * StringUtils.remove("", *)          = ""
    5808     * StringUtils.remove(*, null)        = *
    5809     * StringUtils.remove(*, "")          = *
    5810     * StringUtils.remove("queued", "ue") = "qd"
    5811     * StringUtils.remove("queued", "zz") = "queued"
    5812     * </pre>
    5813     *
    5814     * @param str  the source String to search, may be null
    5815     * @param remove  the String to search for and remove, may be null
    5816     * @return the substring with the string removed if found,
    5817     *  {@code null} if null String input
    5818     * @since 2.1
    5819     */
    5820    public static String remove(final String str, final String remove) {
    5821        if (isEmpty(str) || isEmpty(remove)) {
    5822            return str;
    5823        }
    5824        return replace(str, remove, EMPTY, -1);
    5825    }
    5826
    5827    /**
    5828     * Removes each substring of the text String that matches the given regular expression.
    5829     *
    5830     * This method is a {@code null} safe equivalent to:
    5831     * <ul>
    5832     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
    5833     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
    5834     * </ul>
    5835     *
    5836     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5837     *
    5838     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
    5839     * is NOT automatically added.
    5840     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    5841     * DOTALL is also known as single-line mode in Perl.</p>
    5842     *
    5843     * <pre>
    5844     * StringUtils.removeAll(null, *)      = null
    5845     * StringUtils.removeAll("any", (String) null)  = "any"
    5846     * StringUtils.removeAll("any", "")    = "any"
    5847     * StringUtils.removeAll("any", ".*")  = ""
    5848     * StringUtils.removeAll("any", ".+")  = ""
    5849     * StringUtils.removeAll("abc", ".?")  = ""
    5850     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
    5851     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    5852     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
    5853     * </pre>
    5854     *
    5855     * @param text  text to remove from, may be null
    5856     * @param regex  the regular expression to which this string is to be matched
    5857     * @return  the text with any removes processed,
    5858     *              {@code null} if null String input
    5859     *
    5860     * @throws  java.util.regex.PatternSyntaxException
    5861     *              if the regular expression's syntax is invalid
    5862     *
    5863     * @see #replaceAll(String, String, String)
    5864     * @see #removePattern(String, String)
    5865     * @see String#replaceAll(String, String)
    5866     * @see java.util.regex.Pattern
    5867     * @see java.util.regex.Pattern#DOTALL
    5868     * @since 3.5
    5869     *
    5870     * @deprecated Moved to RegExUtils.
    5871     */
    5872    @Deprecated
    5873    public static String removeAll(final String text, final String regex) {
    5874        return RegExUtils.removeAll(text, regex);
    5875    }
    5876
    5877    /**
    5878     * Removes a substring only if it is at the end of a source string,
    5879     * otherwise returns the source string.
    5880     *
    5881     * <p>A {@code null} source string will return {@code null}.
    5882     * An empty ("") source string will return the empty string.
    5883     * A {@code null} search string will return the source string.</p>
    5884     *
    5885     * <pre>
    5886     * StringUtils.removeEnd(null, *)      = null
    5887     * StringUtils.removeEnd("", *)        = ""
    5888     * StringUtils.removeEnd(*, null)      = *
    5889     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    5890     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    5891     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    5892     * StringUtils.removeEnd("abc", "")    = "abc"
    5893     * </pre>
    5894     *
    5895     * @param str  the source String to search, may be null
    5896     * @param remove  the String to search for and remove, may be null
    5897     * @return the substring with the string removed if found,
    5898     *  {@code null} if null String input
    5899     * @since 2.1
    5900     */
    5901    public static String removeEnd(final String str, final String remove) {
    5902        if (isEmpty(str) || isEmpty(remove)) {
    5903            return str;
    5904        }
    5905        if (str.endsWith(remove)) {
    5906            return str.substring(0, str.length() - remove.length());
    5907        }
    5908        return str;
    5909    }
    5910
    5911    /**
    5912     * Case insensitive removal of a substring if it is at the end of a source string,
    5913     * otherwise returns the source string.
    5914     *
    5915     * <p>A {@code null} source string will return {@code null}.
    5916     * An empty ("") source string will return the empty string.
    5917     * A {@code null} search string will return the source string.</p>
    5918     *
    5919     * <pre>
    5920     * StringUtils.removeEndIgnoreCase(null, *)      = null
    5921     * StringUtils.removeEndIgnoreCase("", *)        = ""
    5922     * StringUtils.removeEndIgnoreCase(*, null)      = *
    5923     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    5924     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    5925     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    5926     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    5927     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    5928     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    5929     * </pre>
    5930     *
    5931     * @param str  the source String to search, may be null
    5932     * @param remove  the String to search for (case-insensitive) and remove, may be null
    5933     * @return the substring with the string removed if found,
    5934     *  {@code null} if null String input
    5935     * @since 2.4
    5936     */
    5937    public static String removeEndIgnoreCase(final String str, final String remove) {
    5938        if (isEmpty(str) || isEmpty(remove)) {
    5939            return str;
    5940        }
    5941        if (endsWithIgnoreCase(str, remove)) {
    5942            return str.substring(0, str.length() - remove.length());
    5943        }
    5944        return str;
    5945    }
    5946
    5947    /**
    5948     * Removes the first substring of the text string that matches the given regular expression.
    5949     *
    5950     * This method is a {@code null} safe equivalent to:
    5951     * <ul>
    5952     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
    5953     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
    5954     * </ul>
    5955     *
    5956     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5957     *
    5958     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    5959     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    5960     * DOTALL is also known as single-line mode in Perl.</p>
    5961     *
    5962     * <pre>
    5963     * StringUtils.removeFirst(null, *)      = null
    5964     * StringUtils.removeFirst("any", (String) null)  = "any"
    5965     * StringUtils.removeFirst("any", "")    = "any"
    5966     * StringUtils.removeFirst("any", ".*")  = ""
    5967     * StringUtils.removeFirst("any", ".+")  = ""
    5968     * StringUtils.removeFirst("abc", ".?")  = "bc"
    5969     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
    5970     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    5971     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
    5972     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
    5973     * </pre>
    5974     *
    5975     * @param text  text to remove from, may be null
    5976     * @param regex  the regular expression to which this string is to be matched
    5977     * @return  the text with the first replacement processed,
    5978     *              {@code null} if null String input
    5979     *
    5980     * @throws  java.util.regex.PatternSyntaxException
    5981     *              if the regular expression's syntax is invalid
    5982     *
    5983     * @see #replaceFirst(String, String, String)
    5984     * @see String#replaceFirst(String, String)
    5985     * @see java.util.regex.Pattern
    5986     * @see java.util.regex.Pattern#DOTALL
    5987     * @since 3.5
    5988     *
    5989     * @deprecated Moved to RegExUtils.
    5990     */
    5991    @Deprecated
    5992    public static String removeFirst(final String text, final String regex) {
    5993        return replaceFirst(text, regex, EMPTY);
    5994    }
    5995
    5996    /**
    5997     * Case insensitive removal of all occurrences of a substring from within
    5998     * the source string.
    5999     *
    6000     * <p>
    6001     * A {@code null} source string will return {@code null}. An empty ("")
    6002     * source string will return the empty string. A {@code null} remove string
    6003     * will return the source string. An empty ("") remove string will return
    6004     * the source string.
    6005     * </p>
    6006     *
    6007     * <pre>
    6008     * StringUtils.removeIgnoreCase(null, *)        = null
    6009     * StringUtils.removeIgnoreCase("", *)          = ""
    6010     * StringUtils.removeIgnoreCase(*, null)        = *
    6011     * StringUtils.removeIgnoreCase(*, "")          = *
    6012     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
    6013     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
    6014     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
    6015     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
    6016     * </pre>
    6017     *
    6018     * @param str
    6019     *            the source String to search, may be null
    6020     * @param remove
    6021     *            the String to search for (case-insensitive) and remove, may be
    6022     *            null
    6023     * @return the substring with the string removed if found, {@code null} if
    6024     *         null String input
    6025     * @since 3.5
    6026     */
    6027    public static String removeIgnoreCase(final String str, final String remove) {
    6028        return replaceIgnoreCase(str, remove, EMPTY, -1);
    6029    }
    6030
    6031    /**
    6032     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
    6033     *
    6034     * This call is a {@code null} safe equivalent to:
    6035     * <ul>
    6036     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
    6037     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
    6038     * </ul>
    6039     *
    6040     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6041     *
    6042     * <pre>
    6043     * StringUtils.removePattern(null, *)       = null
    6044     * StringUtils.removePattern("any", (String) null)   = "any"
    6045     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
    6046     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
    6047     * </pre>
    6048     *
    6049     * @param source
    6050     *            the source string
    6051     * @param regex
    6052     *            the regular expression to which this string is to be matched
    6053     * @return The resulting {@link String}
    6054     * @see #replacePattern(String, String, String)
    6055     * @see String#replaceAll(String, String)
    6056     * @see Pattern#DOTALL
    6057     * @since 3.2
    6058     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    6059     *
    6060     * @deprecated Moved to RegExUtils.
    6061     */
    6062    @Deprecated
    6063    public static String removePattern(final String source, final String regex) {
    6064        return RegExUtils.removePattern(source, regex);
    6065    }
    6066
    6067    /**
    6068     * Removes a char only if it is at the beginning of a source string,
    6069     * otherwise returns the source string.
    6070     *
    6071     * <p>A {@code null} source string will return {@code null}.
    6072     * An empty ("") source string will return the empty string.
    6073     * A {@code null} search char will return the source string.</p>
    6074     *
    6075     * <pre>
    6076     * StringUtils.removeStart(null, *)      = null
    6077     * StringUtils.removeStart("", *)        = ""
    6078     * StringUtils.removeStart(*, null)      = *
    6079     * StringUtils.removeStart("/path", '/') = "path"
    6080     * StringUtils.removeStart("path", '/')  = "path"
    6081     * StringUtils.removeStart("path", 0)    = "path"
    6082     * </pre>
    6083     *
    6084     * @param str  the source String to search, may be null.
    6085     * @param remove  the char to search for and remove.
    6086     * @return the substring with the char removed if found,
    6087     *  {@code null} if null String input.
    6088     * @since 3.13.0
    6089     */
    6090    public static String removeStart(final String str, final char remove) {
    6091        if (isEmpty(str)) {
    6092            return str;
    6093        }
    6094        return str.charAt(0) == remove ? str.substring(1) : str;
    6095    }
    6096
    6097    /**
    6098     * Removes a substring only if it is at the beginning of a source string,
    6099     * otherwise returns the source string.
    6100     *
    6101     * <p>A {@code null} source string will return {@code null}.
    6102     * An empty ("") source string will return the empty string.
    6103     * A {@code null} search string will return the source string.</p>
    6104     *
    6105     * <pre>
    6106     * StringUtils.removeStart(null, *)      = null
    6107     * StringUtils.removeStart("", *)        = ""
    6108     * StringUtils.removeStart(*, null)      = *
    6109     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    6110     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    6111     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    6112     * StringUtils.removeStart("abc", "")    = "abc"
    6113     * </pre>
    6114     *
    6115     * @param str  the source String to search, may be null
    6116     * @param remove  the String to search for and remove, may be null
    6117     * @return the substring with the string removed if found,
    6118     *  {@code null} if null String input
    6119     * @since 2.1
    6120     */
    6121    public static String removeStart(final String str, final String remove) {
    6122        if (isEmpty(str) || isEmpty(remove)) {
    6123            return str;
    6124        }
    6125        if (str.startsWith(remove)) {
    6126            return str.substring(remove.length());
    6127        }
    6128        return str;
    6129    }
    6130
    6131    /**
    6132     * Case insensitive removal of a substring if it is at the beginning of a source string,
    6133     * otherwise returns the source string.
    6134     *
    6135     * <p>A {@code null} source string will return {@code null}.
    6136     * An empty ("") source string will return the empty string.
    6137     * A {@code null} search string will return the source string.</p>
    6138     *
    6139     * <pre>
    6140     * StringUtils.removeStartIgnoreCase(null, *)      = null
    6141     * StringUtils.removeStartIgnoreCase("", *)        = ""
    6142     * StringUtils.removeStartIgnoreCase(*, null)      = *
    6143     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
    6144     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
    6145     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
    6146     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    6147     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
    6148     * </pre>
    6149     *
    6150     * @param str  the source String to search, may be null
    6151     * @param remove  the String to search for (case-insensitive) and remove, may be null
    6152     * @return the substring with the string removed if found,
    6153     *  {@code null} if null String input
    6154     * @since 2.4
    6155     */
    6156    public static String removeStartIgnoreCase(final String str, final String remove) {
    6157        if (str != null && startsWithIgnoreCase(str, remove)) {
    6158            return str.substring(length(remove));
    6159        }
    6160        return str;
    6161    }
    6162
    6163    /**
    6164     * Returns padding using the specified delimiter repeated
    6165     * to a given length.
    6166     *
    6167     * <pre>
    6168     * StringUtils.repeat('e', 0)  = ""
    6169     * StringUtils.repeat('e', 3)  = "eee"
    6170     * StringUtils.repeat('e', -2) = ""
    6171     * </pre>
    6172     *
    6173     * <p>Note: this method does not support padding with
    6174     * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    6175     * as they require a pair of {@code char}s to be represented.
    6176     * If you are needing to support full I18N of your applications
    6177     * consider using {@link #repeat(String, int)} instead.
    6178     * </p>
    6179     *
    6180     * @param ch  character to repeat
    6181     * @param repeat  number of times to repeat char, negative treated as zero
    6182     * @return String with repeated character
    6183     * @see #repeat(String, int)
    6184     */
    6185    public static String repeat(final char ch, final int repeat) {
    6186        if (repeat <= 0) {
    6187            return EMPTY;
    6188        }
    6189        final char[] buf = new char[repeat];
    6190        Arrays.fill(buf, ch);
    6191        return new String(buf);
    6192    }
    6193
    6194    /**
    6195     * Repeat a String {@code repeat} times to form a
    6196     * new String.
    6197     *
    6198     * <pre>
    6199     * StringUtils.repeat(null, 2) = null
    6200     * StringUtils.repeat("", 0)   = ""
    6201     * StringUtils.repeat("", 2)   = ""
    6202     * StringUtils.repeat("a", 3)  = "aaa"
    6203     * StringUtils.repeat("ab", 2) = "abab"
    6204     * StringUtils.repeat("a", -2) = ""
    6205     * </pre>
    6206     *
    6207     * @param str  the String to repeat, may be null
    6208     * @param repeat  number of times to repeat str, negative treated as zero
    6209     * @return a new String consisting of the original String repeated,
    6210     *  {@code null} if null String input
    6211     */
    6212    public static String repeat(final String str, final int repeat) {
    6213        // Performance tuned for 2.0 (JDK1.4)
    6214        if (str == null) {
    6215            return null;
    6216        }
    6217        if (repeat <= 0) {
    6218            return EMPTY;
    6219        }
    6220        final int inputLength = str.length();
    6221        if (repeat == 1 || inputLength == 0) {
    6222            return str;
    6223        }
    6224        if (inputLength == 1 && repeat <= PAD_LIMIT) {
    6225            return repeat(str.charAt(0), repeat);
    6226        }
    6227
    6228        final int outputLength = inputLength * repeat;
    6229        switch (inputLength) {
    6230            case 1 :
    6231                return repeat(str.charAt(0), repeat);
    6232            case 2 :
    6233                final char ch0 = str.charAt(0);
    6234                final char ch1 = str.charAt(1);
    6235                final char[] output2 = new char[outputLength];
    6236                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
    6237                    output2[i] = ch0;
    6238                    output2[i + 1] = ch1;
    6239                }
    6240                return new String(output2);
    6241            default :
    6242                final StringBuilder buf = new StringBuilder(outputLength);
    6243                for (int i = 0; i < repeat; i++) {
    6244                    buf.append(str);
    6245                }
    6246                return buf.toString();
    6247        }
    6248    }
    6249
    6250    /**
    6251     * Repeat a String {@code repeat} times to form a
    6252     * new String, with a String separator injected each time.
    6253     *
    6254     * <pre>
    6255     * StringUtils.repeat(null, null, 2) = null
    6256     * StringUtils.repeat(null, "x", 2)  = null
    6257     * StringUtils.repeat("", null, 0)   = ""
    6258     * StringUtils.repeat("", "", 2)     = ""
    6259     * StringUtils.repeat("", "x", 3)    = "xx"
    6260     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    6261     * </pre>
    6262     *
    6263     * @param str        the String to repeat, may be null
    6264     * @param separator  the String to inject, may be null
    6265     * @param repeat     number of times to repeat str, negative treated as zero
    6266     * @return a new String consisting of the original String repeated,
    6267     *  {@code null} if null String input
    6268     * @since 2.5
    6269     */
    6270    public static String repeat(final String str, final String separator, final int repeat) {
    6271        if (str == null || separator == null) {
    6272            return repeat(str, repeat);
    6273        }
    6274        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    6275        final String result = repeat(str + separator, repeat);
    6276        return removeEnd(result, separator);
    6277    }
    6278
    6279    /**
    6280     * Replaces all occurrences of a String within another String.
    6281     *
    6282     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6283     *
    6284     * <pre>
    6285     * StringUtils.replace(null, *, *)        = null
    6286     * StringUtils.replace("", *, *)          = ""
    6287     * StringUtils.replace("any", null, *)    = "any"
    6288     * StringUtils.replace("any", *, null)    = "any"
    6289     * StringUtils.replace("any", "", *)      = "any"
    6290     * StringUtils.replace("aba", "a", null)  = "aba"
    6291     * StringUtils.replace("aba", "a", "")    = "b"
    6292     * StringUtils.replace("aba", "a", "z")   = "zbz"
    6293     * </pre>
    6294     *
    6295     * @see #replace(String text, String searchString, String replacement, int max)
    6296     * @param text  text to search and replace in, may be null
    6297     * @param searchString  the String to search for, may be null
    6298     * @param replacement  the String to replace it with, may be null
    6299     * @return the text with any replacements processed,
    6300     *  {@code null} if null String input
    6301     */
    6302    public static String replace(final String text, final String searchString, final String replacement) {
    6303        return replace(text, searchString, replacement, -1);
    6304    }
    6305
    6306    /**
    6307     * Replaces a String with another String inside a larger String,
    6308     * for the first {@code max} values of the search String.
    6309     *
    6310     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6311     *
    6312     * <pre>
    6313     * StringUtils.replace(null, *, *, *)         = null
    6314     * StringUtils.replace("", *, *, *)           = ""
    6315     * StringUtils.replace("any", null, *, *)     = "any"
    6316     * StringUtils.replace("any", *, null, *)     = "any"
    6317     * StringUtils.replace("any", "", *, *)       = "any"
    6318     * StringUtils.replace("any", *, *, 0)        = "any"
    6319     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    6320     * StringUtils.replace("abaa", "a", "", -1)   = "b"
    6321     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    6322     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    6323     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    6324     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    6325     * </pre>
    6326     *
    6327     * @param text  text to search and replace in, may be null
    6328     * @param searchString  the String to search for, may be null
    6329     * @param replacement  the String to replace it with, may be null
    6330     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6331     * @return the text with any replacements processed,
    6332     *  {@code null} if null String input
    6333     */
    6334    public static String replace(final String text, final String searchString, final String replacement, final int max) {
    6335        return replace(text, searchString, replacement, max, false);
    6336    }
    6337
    6338    /**
    6339     * Replaces a String with another String inside a larger String,
    6340     * for the first {@code max} values of the search String,
    6341     * case-sensitively/insensitively based on {@code ignoreCase} value.
    6342     *
    6343     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6344     *
    6345     * <pre>
    6346     * StringUtils.replace(null, *, *, *, false)         = null
    6347     * StringUtils.replace("", *, *, *, false)           = ""
    6348     * StringUtils.replace("any", null, *, *, false)     = "any"
    6349     * StringUtils.replace("any", *, null, *, false)     = "any"
    6350     * StringUtils.replace("any", "", *, *, false)       = "any"
    6351     * StringUtils.replace("any", *, *, 0, false)        = "any"
    6352     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
    6353     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
    6354     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
    6355     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
    6356     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
    6357     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
    6358     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
    6359     * </pre>
    6360     *
    6361     * @param text  text to search and replace in, may be null
    6362     * @param searchString  the String to search for (case-insensitive), may be null
    6363     * @param replacement  the String to replace it with, may be null
    6364     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6365     * @param ignoreCase if true replace is case-insensitive, otherwise case-sensitive
    6366     * @return the text with any replacements processed,
    6367     *  {@code null} if null String input
    6368     */
    6369     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
    6370         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
    6371             return text;
    6372         }
    6373         if (ignoreCase) {
    6374             searchString = searchString.toLowerCase();
    6375         }
    6376         int start = 0;
    6377         int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
    6378         if (end == INDEX_NOT_FOUND) {
    6379             return text;
    6380         }
    6381         final int replLength = searchString.length();
    6382         int increase = Math.max(replacement.length() - replLength, 0);
    6383         increase *= max < 0 ? 16 : Math.min(max, 64);
    6384         final StringBuilder buf = new StringBuilder(text.length() + increase);
    6385         while (end != INDEX_NOT_FOUND) {
    6386             buf.append(text, start, end).append(replacement);
    6387             start = end + replLength;
    6388             if (--max == 0) {
    6389                 break;
    6390             }
    6391             end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
    6392         }
    6393         buf.append(text, start, text.length());
    6394         return buf.toString();
    6395     }
    6396
    6397    /**
    6398     * Replaces each substring of the text String that matches the given regular expression
    6399     * with the given replacement.
    6400     *
    6401     * This method is a {@code null} safe equivalent to:
    6402     * <ul>
    6403     *  <li>{@code text.replaceAll(regex, replacement)}</li>
    6404     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
    6405     * </ul>
    6406     *
    6407     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6408     *
    6409     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
    6410     * is NOT automatically added.
    6411     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6412     * DOTALL is also known as single-line mode in Perl.</p>
    6413     *
    6414     * <pre>
    6415     * StringUtils.replaceAll(null, *, *)       = null
    6416     * StringUtils.replaceAll("any", (String) null, *)   = "any"
    6417     * StringUtils.replaceAll("any", *, null)   = "any"
    6418     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
    6419     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
    6420     * StringUtils.replaceAll("", ".+", "zzz")  = ""
    6421     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
    6422     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
    6423     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    6424     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
    6425     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    6426     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    6427     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6428     * </pre>
    6429     *
    6430     * @param text  text to search and replace in, may be null
    6431     * @param regex  the regular expression to which this string is to be matched
    6432     * @param replacement  the string to be substituted for each match
    6433     * @return  the text with any replacements processed,
    6434     *              {@code null} if null String input
    6435     *
    6436     * @throws  java.util.regex.PatternSyntaxException
    6437     *              if the regular expression's syntax is invalid
    6438     *
    6439     * @see #replacePattern(String, String, String)
    6440     * @see String#replaceAll(String, String)
    6441     * @see java.util.regex.Pattern
    6442     * @see java.util.regex.Pattern#DOTALL
    6443     * @since 3.5
    6444     *
    6445     * @deprecated Moved to RegExUtils.
    6446     */
    6447    @Deprecated
    6448    public static String replaceAll(final String text, final String regex, final String replacement) {
    6449        return RegExUtils.replaceAll(text, regex, replacement);
    6450    }
    6451
    6452    /**
    6453     * Replaces all occurrences of a character in a String with another.
    6454     * This is a null-safe version of {@link String#replace(char, char)}.
    6455     *
    6456     * <p>A {@code null} string input returns {@code null}.
    6457     * An empty ("") string input returns an empty string.</p>
    6458     *
    6459     * <pre>
    6460     * StringUtils.replaceChars(null, *, *)        = null
    6461     * StringUtils.replaceChars("", *, *)          = ""
    6462     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    6463     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    6464     * </pre>
    6465     *
    6466     * @param str  String to replace characters in, may be null
    6467     * @param searchChar  the character to search for, may be null
    6468     * @param replaceChar  the character to replace, may be null
    6469     * @return modified String, {@code null} if null string input
    6470     * @since 2.0
    6471     */
    6472    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
    6473        if (str == null) {
    6474            return null;
    6475        }
    6476        return str.replace(searchChar, replaceChar);
    6477    }
    6478
    6479    /**
    6480     * Replaces multiple characters in a String in one go.
    6481     * This method can also be used to delete characters.
    6482     *
    6483     * <p>For example:<br>
    6484     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
    6485     *
    6486     * <p>A {@code null} string input returns {@code null}.
    6487     * An empty ("") string input returns an empty string.
    6488     * A null or empty set of search characters returns the input string.</p>
    6489     *
    6490     * <p>The length of the search characters should normally equal the length
    6491     * of the replace characters.
    6492     * If the search characters is longer, then the extra search characters
    6493     * are deleted.
    6494     * If the search characters is shorter, then the extra replace characters
    6495     * are ignored.</p>
    6496     *
    6497     * <pre>
    6498     * StringUtils.replaceChars(null, *, *)           = null
    6499     * StringUtils.replaceChars("", *, *)             = ""
    6500     * StringUtils.replaceChars("abc", null, *)       = "abc"
    6501     * StringUtils.replaceChars("abc", "", *)         = "abc"
    6502     * StringUtils.replaceChars("abc", "b", null)     = "ac"
    6503     * StringUtils.replaceChars("abc", "b", "")       = "ac"
    6504     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    6505     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    6506     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    6507     * </pre>
    6508     *
    6509     * @param str  String to replace characters in, may be null
    6510     * @param searchChars  a set of characters to search for, may be null
    6511     * @param replaceChars  a set of characters to replace, may be null
    6512     * @return modified String, {@code null} if null string input
    6513     * @since 2.0
    6514     */
    6515    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
    6516        if (isEmpty(str) || isEmpty(searchChars)) {
    6517            return str;
    6518        }
    6519        if (replaceChars == null) {
    6520            replaceChars = EMPTY;
    6521        }
    6522        boolean modified = false;
    6523        final int replaceCharsLength = replaceChars.length();
    6524        final int strLength = str.length();
    6525        final StringBuilder buf = new StringBuilder(strLength);
    6526        for (int i = 0; i < strLength; i++) {
    6527            final char ch = str.charAt(i);
    6528            final int index = searchChars.indexOf(ch);
    6529            if (index >= 0) {
    6530                modified = true;
    6531                if (index < replaceCharsLength) {
    6532                    buf.append(replaceChars.charAt(index));
    6533                }
    6534            } else {
    6535                buf.append(ch);
    6536            }
    6537        }
    6538        if (modified) {
    6539            return buf.toString();
    6540        }
    6541        return str;
    6542    }
    6543
    6544    /**
    6545     * Replaces all occurrences of Strings within another String.
    6546     *
    6547     * <p>
    6548     * A {@code null} reference passed to this method is a no-op, or if
    6549     * any "search string" or "string to replace" is null, that replace will be
    6550     * ignored. This will not repeat. For repeating replaces, call the
    6551     * overloaded method.
    6552     * </p>
    6553     *
    6554     * <pre>
    6555     *  StringUtils.replaceEach(null, *, *)        = null
    6556     *  StringUtils.replaceEach("", *, *)          = ""
    6557     *  StringUtils.replaceEach("aba", null, null) = "aba"
    6558     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
    6559     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
    6560     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
    6561     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
    6562     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
    6563     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    6564     *  (example of how it does not repeat)
    6565     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    6566     * </pre>
    6567     *
    6568     * @param text
    6569     *            text to search and replace in, no-op if null
    6570     * @param searchList
    6571     *            the Strings to search for, no-op if null
    6572     * @param replacementList
    6573     *            the Strings to replace them with, no-op if null
    6574     * @return the text with any replacements processed, {@code null} if
    6575     *         null String input
    6576     * @throws IllegalArgumentException
    6577     *             if the lengths of the arrays are not the same (null is ok,
    6578     *             and/or size 0)
    6579     * @since 2.4
    6580     */
    6581    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
    6582        return replaceEach(text, searchList, replacementList, false, 0);
    6583    }
    6584
    6585    /**
    6586     * Replace all occurrences of Strings within another String.
    6587     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
    6588     * {@link #replaceEach(String, String[], String[])}
    6589     *
    6590     * <p>
    6591     * A {@code null} reference passed to this method is a no-op, or if
    6592     * any "search string" or "string to replace" is null, that replace will be
    6593     * ignored.
    6594     * </p>
    6595     *
    6596     * <pre>
    6597     *  StringUtils.replaceEach(null, *, *, *, *) = null
    6598     *  StringUtils.replaceEach("", *, *, *, *) = ""
    6599     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
    6600     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
    6601     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
    6602     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
    6603     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
    6604     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
    6605     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
    6606     *  (example of how it repeats)
    6607     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
    6608     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
    6609     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
    6610     * </pre>
    6611     *
    6612     * @param text
    6613     *            text to search and replace in, no-op if null
    6614     * @param searchList
    6615     *            the Strings to search for, no-op if null
    6616     * @param replacementList
    6617     *            the Strings to replace them with, no-op if null
    6618     * @param repeat if true, then replace repeatedly
    6619     *       until there are no more possible replacements or timeToLive < 0
    6620     * @param timeToLive
    6621     *            if less than 0 then there is a circular reference and endless
    6622     *            loop
    6623     * @return the text with any replacements processed, {@code null} if
    6624     *         null String input
    6625     * @throws IllegalStateException
    6626     *             if the search is repeating and there is an endless loop due
    6627     *             to outputs of one being inputs to another
    6628     * @throws IllegalArgumentException
    6629     *             if the lengths of the arrays are not the same (null is ok,
    6630     *             and/or size 0)
    6631     * @since 2.4
    6632     */
    6633    private static String replaceEach(
    6634            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
    6635
    6636        // mchyzer Performance note: This creates very few new objects (one major goal)
    6637        // let me know if there are performance requests, we can create a harness to measure
    6638
    6639        // if recursing, this shouldn't be less than 0
    6640        if (timeToLive < 0) {
    6641            final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
    6642            final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
    6643            searchSet.retainAll(replacementSet);
    6644            if (!searchSet.isEmpty()) {
    6645                throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
    6646                        "output of one loop is the input of another");
    6647            }
    6648        }
    6649
    6650        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || ArrayUtils.isNotEmpty(searchList) && timeToLive == -1) {
    6651            return text;
    6652        }
    6653
    6654        final int searchLength = searchList.length;
    6655        final int replacementLength = replacementList.length;
    6656
    6657        // make sure lengths are ok, these need to be equal
    6658        if (searchLength != replacementLength) {
    6659            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    6660                + searchLength
    6661                + " vs "
    6662                + replacementLength);
    6663        }
    6664
    6665        // keep track of which still have matches
    6666        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    6667
    6668        // index on index that the match was found
    6669        int textIndex = -1;
    6670        int replaceIndex = -1;
    6671        int tempIndex;
    6672
    6673        // index of replace array that will replace the search string found
    6674        // NOTE: logic duplicated below START
    6675        for (int i = 0; i < searchLength; i++) {
    6676            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6677                continue;
    6678            }
    6679            tempIndex = text.indexOf(searchList[i]);
    6680
    6681            // see if we need to keep searching for this
    6682            if (tempIndex == -1) {
    6683                noMoreMatchesForReplIndex[i] = true;
    6684            } else if (textIndex == -1 || tempIndex < textIndex) {
    6685                textIndex = tempIndex;
    6686                replaceIndex = i;
    6687            }
    6688        }
    6689        // NOTE: logic mostly below END
    6690
    6691        // no search strings found, we are done
    6692        if (textIndex == -1) {
    6693            return text;
    6694        }
    6695
    6696        int start = 0;
    6697
    6698        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
    6699        int increase = 0;
    6700
    6701        // count the replacement text elements that are larger than their corresponding text being replaced
    6702        for (int i = 0; i < searchList.length; i++) {
    6703            if (searchList[i] == null || replacementList[i] == null) {
    6704                continue;
    6705            }
    6706            final int greater = replacementList[i].length() - searchList[i].length();
    6707            if (greater > 0) {
    6708                increase += 3 * greater; // assume 3 matches
    6709            }
    6710        }
    6711        // have upper-bound at 20% increase, then let Java take over
    6712        increase = Math.min(increase, text.length() / 5);
    6713
    6714        final StringBuilder buf = new StringBuilder(text.length() + increase);
    6715
    6716        while (textIndex != -1) {
    6717
    6718            for (int i = start; i < textIndex; i++) {
    6719                buf.append(text.charAt(i));
    6720            }
    6721            buf.append(replacementList[replaceIndex]);
    6722
    6723            start = textIndex + searchList[replaceIndex].length();
    6724
    6725            textIndex = -1;
    6726            replaceIndex = -1;
    6727            // find the next earliest match
    6728            // NOTE: logic mostly duplicated above START
    6729            for (int i = 0; i < searchLength; i++) {
    6730                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6731                    continue;
    6732                }
    6733                tempIndex = text.indexOf(searchList[i], start);
    6734
    6735                // see if we need to keep searching for this
    6736                if (tempIndex == -1) {
    6737                    noMoreMatchesForReplIndex[i] = true;
    6738                } else if (textIndex == -1 || tempIndex < textIndex) {
    6739                    textIndex = tempIndex;
    6740                    replaceIndex = i;
    6741                }
    6742            }
    6743            // NOTE: logic duplicated above END
    6744
    6745        }
    6746        final int textLength = text.length();
    6747        for (int i = start; i < textLength; i++) {
    6748            buf.append(text.charAt(i));
    6749        }
    6750        final String result = buf.toString();
    6751        if (!repeat) {
    6752            return result;
    6753        }
    6754
    6755        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    6756    }
    6757
    6758    /**
    6759     * Replaces all occurrences of Strings within another String.
    6760     *
    6761     * <p>
    6762     * A {@code null} reference passed to this method is a no-op, or if
    6763     * any "search string" or "string to replace" is null, that replace will be
    6764     * ignored.
    6765     * </p>
    6766     *
    6767     * <pre>
    6768     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
    6769     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
    6770     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
    6771     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
    6772     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
    6773     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
    6774     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
    6775     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
    6776     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
    6777     *  (example of how it repeats)
    6778     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
    6779     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
    6780     * </pre>
    6781     *
    6782     * @param text
    6783     *            text to search and replace in, no-op if null
    6784     * @param searchList
    6785     *            the Strings to search for, no-op if null
    6786     * @param replacementList
    6787     *            the Strings to replace them with, no-op if null
    6788     * @return the text with any replacements processed, {@code null} if
    6789     *         null String input
    6790     * @throws IllegalStateException
    6791     *             if the search is repeating and there is an endless loop due
    6792     *             to outputs of one being inputs to another
    6793     * @throws IllegalArgumentException
    6794     *             if the lengths of the arrays are not the same (null is ok,
    6795     *             and/or size 0)
    6796     * @since 2.4
    6797     */
    6798    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
    6799        return replaceEach(text, searchList, replacementList, true, ArrayUtils.getLength(searchList));
    6800    }
    6801
    6802    /**
    6803     * Replaces the first substring of the text string that matches the given regular expression
    6804     * with the given replacement.
    6805     *
    6806     * This method is a {@code null} safe equivalent to:
    6807     * <ul>
    6808     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
    6809     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
    6810     * </ul>
    6811     *
    6812     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6813     *
    6814     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    6815     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6816     * DOTALL is also known as single-line mode in Perl.</p>
    6817     *
    6818     * <pre>
    6819     * StringUtils.replaceFirst(null, *, *)       = null
    6820     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
    6821     * StringUtils.replaceFirst("any", *, null)   = "any"
    6822     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
    6823     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
    6824     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
    6825     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
    6826     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
    6827     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    6828     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
    6829     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
    6830     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
    6831     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
    6832     * </pre>
    6833     *
    6834     * @param text  text to search and replace in, may be null
    6835     * @param regex  the regular expression to which this string is to be matched
    6836     * @param replacement  the string to be substituted for the first match
    6837     * @return  the text with the first replacement processed,
    6838     *              {@code null} if null String input
    6839     *
    6840     * @throws  java.util.regex.PatternSyntaxException
    6841     *              if the regular expression's syntax is invalid
    6842     *
    6843     * @see String#replaceFirst(String, String)
    6844     * @see java.util.regex.Pattern
    6845     * @see java.util.regex.Pattern#DOTALL
    6846     * @since 3.5
    6847     *
    6848     * @deprecated Moved to RegExUtils.
    6849     */
    6850    @Deprecated
    6851    public static String replaceFirst(final String text, final String regex, final String replacement) {
    6852        return RegExUtils.replaceFirst(text, regex, replacement);
    6853    }
    6854
    6855    /**
    6856     * Case insensitively replaces all occurrences of a String within another String.
    6857     *
    6858     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6859     *
    6860     * <pre>
    6861     * StringUtils.replaceIgnoreCase(null, *, *)        = null
    6862     * StringUtils.replaceIgnoreCase("", *, *)          = ""
    6863     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
    6864     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
    6865     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
    6866     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
    6867     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
    6868     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
    6869     * </pre>
    6870     *
    6871     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6872     * @param text  text to search and replace in, may be null
    6873     * @param searchString  the String to search for (case-insensitive), may be null
    6874     * @param replacement  the String to replace it with, may be null
    6875     * @return the text with any replacements processed,
    6876     *  {@code null} if null String input
    6877     * @since 3.5
    6878     */
    6879     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
    6880         return replaceIgnoreCase(text, searchString, replacement, -1);
    6881     }
    6882
    6883    /**
    6884     * Case insensitively replaces a String with another String inside a larger String,
    6885     * for the first {@code max} values of the search String.
    6886     *
    6887     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6888     *
    6889     * <pre>
    6890     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
    6891     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
    6892     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
    6893     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
    6894     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
    6895     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
    6896     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
    6897     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
    6898     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
    6899     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
    6900     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
    6901     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
    6902     * </pre>
    6903     *
    6904     * @param text  text to search and replace in, may be null
    6905     * @param searchString  the String to search for (case-insensitive), may be null
    6906     * @param replacement  the String to replace it with, may be null
    6907     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6908     * @return the text with any replacements processed,
    6909     *  {@code null} if null String input
    6910     * @since 3.5
    6911     */
    6912    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
    6913        return replace(text, searchString, replacement, max, true);
    6914    }
    6915
    6916    /**
    6917     * Replaces a String with another String inside a larger String, once.
    6918     *
    6919     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6920     *
    6921     * <pre>
    6922     * StringUtils.replaceOnce(null, *, *)        = null
    6923     * StringUtils.replaceOnce("", *, *)          = ""
    6924     * StringUtils.replaceOnce("any", null, *)    = "any"
    6925     * StringUtils.replaceOnce("any", *, null)    = "any"
    6926     * StringUtils.replaceOnce("any", "", *)      = "any"
    6927     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    6928     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    6929     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    6930     * </pre>
    6931     *
    6932     * @see #replace(String text, String searchString, String replacement, int max)
    6933     * @param text  text to search and replace in, may be null
    6934     * @param searchString  the String to search for, may be null
    6935     * @param replacement  the String to replace with, may be null
    6936     * @return the text with any replacements processed,
    6937     *  {@code null} if null String input
    6938     */
    6939    public static String replaceOnce(final String text, final String searchString, final String replacement) {
    6940        return replace(text, searchString, replacement, 1);
    6941    }
    6942
    6943    /**
    6944     * Case insensitively replaces a String with another String inside a larger String, once.
    6945     *
    6946     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6947     *
    6948     * <pre>
    6949     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
    6950     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
    6951     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
    6952     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
    6953     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
    6954     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
    6955     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
    6956     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
    6957     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
    6958     * </pre>
    6959     *
    6960     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6961     * @param text  text to search and replace in, may be null
    6962     * @param searchString  the String to search for (case-insensitive), may be null
    6963     * @param replacement  the String to replace with, may be null
    6964     * @return the text with any replacements processed,
    6965     *  {@code null} if null String input
    6966     * @since 3.5
    6967     */
    6968    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
    6969        return replaceIgnoreCase(text, searchString, replacement, 1);
    6970    }
    6971
    6972    /**
    6973     * Replaces each substring of the source String that matches the given regular expression with the given
    6974     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
    6975     *
    6976     * This call is a {@code null} safe equivalent to:
    6977     * <ul>
    6978     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
    6979     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
    6980     * </ul>
    6981     *
    6982     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6983     *
    6984     * <pre>
    6985     * StringUtils.replacePattern(null, *, *)       = null
    6986     * StringUtils.replacePattern("any", (String) null, *)   = "any"
    6987     * StringUtils.replacePattern("any", *, null)   = "any"
    6988     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
    6989     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
    6990     * StringUtils.replacePattern("", ".+", "zzz")  = ""
    6991     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
    6992     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
    6993     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    6994     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    6995     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6996     * </pre>
    6997     *
    6998     * @param source
    6999     *            the source string
    7000     * @param regex
    7001     *            the regular expression to which this string is to be matched
    7002     * @param replacement
    7003     *            the string to be substituted for each match
    7004     * @return The resulting {@link String}
    7005     * @see #replaceAll(String, String, String)
    7006     * @see String#replaceAll(String, String)
    7007     * @see Pattern#DOTALL
    7008     * @since 3.2
    7009     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    7010     *
    7011     * @deprecated Moved to RegExUtils.
    7012     */
    7013    @Deprecated
    7014    public static String replacePattern(final String source, final String regex, final String replacement) {
    7015        return RegExUtils.replacePattern(source, regex, replacement);
    7016    }
    7017
    7018    /**
    7019     * Reverses a String as per {@link StringBuilder#reverse()}.
    7020     *
    7021     * <p>A {@code null} String returns {@code null}.</p>
    7022     *
    7023     * <pre>
    7024     * StringUtils.reverse(null)  = null
    7025     * StringUtils.reverse("")    = ""
    7026     * StringUtils.reverse("bat") = "tab"
    7027     * </pre>
    7028     *
    7029     * @param str  the String to reverse, may be null
    7030     * @return the reversed String, {@code null} if null String input
    7031     */
    7032    public static String reverse(final String str) {
    7033        if (str == null) {
    7034            return null;
    7035        }
    7036        return new StringBuilder(str).reverse().toString();
    7037    }
    7038
    7039    /**
    7040     * Reverses a String that is delimited by a specific character.
    7041     *
    7042     * <p>The Strings between the delimiters are not reversed.
    7043     * Thus java.lang.String becomes String.lang.java (if the delimiter
    7044     * is {@code '.'}).</p>
    7045     *
    7046     * <pre>
    7047     * StringUtils.reverseDelimited(null, *)      = null
    7048     * StringUtils.reverseDelimited("", *)        = ""
    7049     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    7050     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    7051     * </pre>
    7052     *
    7053     * @param str  the String to reverse, may be null
    7054     * @param separatorChar  the separator character to use
    7055     * @return the reversed String, {@code null} if null String input
    7056     * @since 2.0
    7057     */
    7058    public static String reverseDelimited(final String str, final char separatorChar) {
    7059        if (str == null) {
    7060            return null;
    7061        }
    7062        // could implement manually, but simple way is to reuse other,
    7063        // probably slower, methods.
    7064        final String[] strs = split(str, separatorChar);
    7065        ArrayUtils.reverse(strs);
    7066        return join(strs, separatorChar);
    7067    }
    7068
    7069    /**
    7070     * Gets the rightmost {@code len} characters of a String.
    7071     *
    7072     * <p>If {@code len} characters are not available, or the String
    7073     * is {@code null}, the String will be returned without an
    7074     * an exception. An empty String is returned if len is negative.</p>
    7075     *
    7076     * <pre>
    7077     * StringUtils.right(null, *)    = null
    7078     * StringUtils.right(*, -ve)     = ""
    7079     * StringUtils.right("", *)      = ""
    7080     * StringUtils.right("abc", 0)   = ""
    7081     * StringUtils.right("abc", 2)   = "bc"
    7082     * StringUtils.right("abc", 4)   = "abc"
    7083     * </pre>
    7084     *
    7085     * @param str  the String to get the rightmost characters from, may be null
    7086     * @param len  the length of the required String
    7087     * @return the rightmost characters, {@code null} if null String input
    7088     */
    7089    public static String right(final String str, final int len) {
    7090        if (str == null) {
    7091            return null;
    7092        }
    7093        if (len < 0) {
    7094            return EMPTY;
    7095        }
    7096        if (str.length() <= len) {
    7097            return str;
    7098        }
    7099        return str.substring(str.length() - len);
    7100    }
    7101
    7102    /**
    7103     * Right pad a String with spaces (' ').
    7104     *
    7105     * <p>The String is padded to the size of {@code size}.</p>
    7106     *
    7107     * <pre>
    7108     * StringUtils.rightPad(null, *)   = null
    7109     * StringUtils.rightPad("", 3)     = "   "
    7110     * StringUtils.rightPad("bat", 3)  = "bat"
    7111     * StringUtils.rightPad("bat", 5)  = "bat  "
    7112     * StringUtils.rightPad("bat", 1)  = "bat"
    7113     * StringUtils.rightPad("bat", -1) = "bat"
    7114     * </pre>
    7115     *
    7116     * @param str  the String to pad out, may be null
    7117     * @param size  the size to pad to
    7118     * @return right padded String or original String if no padding is necessary,
    7119     *  {@code null} if null String input
    7120     */
    7121    public static String rightPad(final String str, final int size) {
    7122        return rightPad(str, size, ' ');
    7123    }
    7124
    7125    /**
    7126     * Right pad a String with a specified character.
    7127     *
    7128     * <p>The String is padded to the size of {@code size}.</p>
    7129     *
    7130     * <pre>
    7131     * StringUtils.rightPad(null, *, *)     = null
    7132     * StringUtils.rightPad("", 3, 'z')     = "zzz"
    7133     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    7134     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    7135     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    7136     * StringUtils.rightPad("bat", -1, 'z') = "bat"
    7137     * </pre>
    7138     *
    7139     * @param str  the String to pad out, may be null
    7140     * @param size  the size to pad to
    7141     * @param padChar  the character to pad with
    7142     * @return right padded String or original String if no padding is necessary,
    7143     *  {@code null} if null String input
    7144     * @since 2.0
    7145     */
    7146    public static String rightPad(final String str, final int size, final char padChar) {
    7147        if (str == null) {
    7148            return null;
    7149        }
    7150        final int pads = size - str.length();
    7151        if (pads <= 0) {
    7152            return str; // returns original String when possible
    7153        }
    7154        if (pads > PAD_LIMIT) {
    7155            return rightPad(str, size, String.valueOf(padChar));
    7156        }
    7157        return str.concat(repeat(padChar, pads));
    7158    }
    7159
    7160    /**
    7161     * Right pad a String with a specified String.
    7162     *
    7163     * <p>The String is padded to the size of {@code size}.</p>
    7164     *
    7165     * <pre>
    7166     * StringUtils.rightPad(null, *, *)      = null
    7167     * StringUtils.rightPad("", 3, "z")      = "zzz"
    7168     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    7169     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    7170     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    7171     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    7172     * StringUtils.rightPad("bat", -1, "yz") = "bat"
    7173     * StringUtils.rightPad("bat", 5, null)  = "bat  "
    7174     * StringUtils.rightPad("bat", 5, "")    = "bat  "
    7175     * </pre>
    7176     *
    7177     * @param str  the String to pad out, may be null
    7178     * @param size  the size to pad to
    7179     * @param padStr  the String to pad with, null or empty treated as single space
    7180     * @return right padded String or original String if no padding is necessary,
    7181     *  {@code null} if null String input
    7182     */
    7183    public static String rightPad(final String str, final int size, String padStr) {
    7184        if (str == null) {
    7185            return null;
    7186        }
    7187        if (isEmpty(padStr)) {
    7188            padStr = SPACE;
    7189        }
    7190        final int padLen = padStr.length();
    7191        final int strLen = str.length();
    7192        final int pads = size - strLen;
    7193        if (pads <= 0) {
    7194            return str; // returns original String when possible
    7195        }
    7196        if (padLen == 1 && pads <= PAD_LIMIT) {
    7197            return rightPad(str, size, padStr.charAt(0));
    7198        }
    7199
    7200        if (pads == padLen) {
    7201            return str.concat(padStr);
    7202        }
    7203        if (pads < padLen) {
    7204            return str.concat(padStr.substring(0, pads));
    7205        }
    7206        final char[] padding = new char[pads];
    7207        final char[] padChars = padStr.toCharArray();
    7208        for (int i = 0; i < pads; i++) {
    7209            padding[i] = padChars[i % padLen];
    7210        }
    7211        return str.concat(new String(padding));
    7212    }
    7213
    7214    /**
    7215     * Rotate (circular shift) a String of {@code shift} characters.
    7216     * <ul>
    7217     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
    7218     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
    7219     * </ul>
    7220     *
    7221     * <pre>
    7222     * StringUtils.rotate(null, *)        = null
    7223     * StringUtils.rotate("", *)          = ""
    7224     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
    7225     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
    7226     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
    7227     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
    7228     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
    7229     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
    7230     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
    7231     * </pre>
    7232     *
    7233     * @param str  the String to rotate, may be null
    7234     * @param shift  number of time to shift (positive : right shift, negative : left shift)
    7235     * @return the rotated String,
    7236     *          or the original String if {@code shift == 0},
    7237     *          or {@code null} if null String input
    7238     * @since 3.5
    7239     */
    7240    public static String rotate(final String str, final int shift) {
    7241        if (str == null) {
    7242            return null;
    7243        }
    7244
    7245        final int strLen = str.length();
    7246        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
    7247            return str;
    7248        }
    7249
    7250        final StringBuilder builder = new StringBuilder(strLen);
    7251        final int offset = - (shift % strLen);
    7252        builder.append(substring(str, offset));
    7253        builder.append(substring(str, 0, offset));
    7254        return builder.toString();
    7255    }
    7256
    7257    /**
    7258     * Splits the provided text into an array, using whitespace as the
    7259     * separator.
    7260     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7261     *
    7262     * <p>The separator is not included in the returned String array.
    7263     * Adjacent separators are treated as one separator.
    7264     * For more control over the split use the StrTokenizer class.</p>
    7265     *
    7266     * <p>A {@code null} input String returns {@code null}.</p>
    7267     *
    7268     * <pre>
    7269     * StringUtils.split(null)       = null
    7270     * StringUtils.split("")         = []
    7271     * StringUtils.split("abc def")  = ["abc", "def"]
    7272     * StringUtils.split("abc  def") = ["abc", "def"]
    7273     * StringUtils.split(" abc ")    = ["abc"]
    7274     * </pre>
    7275     *
    7276     * @param str  the String to parse, may be null
    7277     * @return an array of parsed Strings, {@code null} if null String input
    7278     */
    7279    public static String[] split(final String str) {
    7280        return split(str, null, -1);
    7281    }
    7282
    7283    /**
    7284     * Splits the provided text into an array, separator specified.
    7285     * This is an alternative to using StringTokenizer.
    7286     *
    7287     * <p>The separator is not included in the returned String array.
    7288     * Adjacent separators are treated as one separator.
    7289     * For more control over the split use the StrTokenizer class.</p>
    7290     *
    7291     * <p>A {@code null} input String returns {@code null}.</p>
    7292     *
    7293     * <pre>
    7294     * StringUtils.split(null, *)         = null
    7295     * StringUtils.split("", *)           = []
    7296     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    7297     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    7298     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    7299     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    7300     * </pre>
    7301     *
    7302     * @param str  the String to parse, may be null
    7303     * @param separatorChar  the character used as the delimiter
    7304     * @return an array of parsed Strings, {@code null} if null String input
    7305     * @since 2.0
    7306     */
    7307    public static String[] split(final String str, final char separatorChar) {
    7308        return splitWorker(str, separatorChar, false);
    7309    }
    7310
    7311    /**
    7312     * Splits the provided text into an array, separators specified.
    7313     * This is an alternative to using StringTokenizer.
    7314     *
    7315     * <p>The separator is not included in the returned String array.
    7316     * Adjacent separators are treated as one separator.
    7317     * For more control over the split use the StrTokenizer class.</p>
    7318     *
    7319     * <p>A {@code null} input String returns {@code null}.
    7320     * A {@code null} separatorChars splits on whitespace.</p>
    7321     *
    7322     * <pre>
    7323     * StringUtils.split(null, *)         = null
    7324     * StringUtils.split("", *)           = []
    7325     * StringUtils.split("abc def", null) = ["abc", "def"]
    7326     * StringUtils.split("abc def", " ")  = ["abc", "def"]
    7327     * StringUtils.split("abc  def", " ") = ["abc", "def"]
    7328     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    7329     * </pre>
    7330     *
    7331     * @param str  the String to parse, may be null
    7332     * @param separatorChars  the characters used as the delimiters,
    7333     *  {@code null} splits on whitespace
    7334     * @return an array of parsed Strings, {@code null} if null String input
    7335     */
    7336    public static String[] split(final String str, final String separatorChars) {
    7337        return splitWorker(str, separatorChars, -1, false);
    7338    }
    7339
    7340    /**
    7341     * Splits the provided text into an array with a maximum length,
    7342     * separators specified.
    7343     *
    7344     * <p>The separator is not included in the returned String array.
    7345     * Adjacent separators are treated as one separator.</p>
    7346     *
    7347     * <p>A {@code null} input String returns {@code null}.
    7348     * A {@code null} separatorChars splits on whitespace.</p>
    7349     *
    7350     * <p>If more than {@code max} delimited substrings are found, the last
    7351     * returned string includes all characters after the first {@code max - 1}
    7352     * returned strings (including separator characters).</p>
    7353     *
    7354     * <pre>
    7355     * StringUtils.split(null, *, *)            = null
    7356     * StringUtils.split("", *, *)              = []
    7357     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
    7358     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
    7359     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7360     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7361     * </pre>
    7362     *
    7363     * @param str  the String to parse, may be null
    7364     * @param separatorChars  the characters used as the delimiters,
    7365     *  {@code null} splits on whitespace
    7366     * @param max  the maximum number of elements to include in the
    7367     *  array. A zero or negative value implies no limit
    7368     * @return an array of parsed Strings, {@code null} if null String input
    7369     */
    7370    public static String[] split(final String str, final String separatorChars, final int max) {
    7371        return splitWorker(str, separatorChars, max, false);
    7372    }
    7373
    7374    /**
    7375     * Splits a String by Character type as returned by
    7376     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7377     * characters of the same type are returned as complete tokens.
    7378     * <pre>
    7379     * StringUtils.splitByCharacterType(null)         = null
    7380     * StringUtils.splitByCharacterType("")           = []
    7381     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7382     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7383     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7384     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    7385     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    7386     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    7387     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    7388     * </pre>
    7389     * @param str the String to split, may be {@code null}
    7390     * @return an array of parsed Strings, {@code null} if null String input
    7391     * @since 2.4
    7392     */
    7393    public static String[] splitByCharacterType(final String str) {
    7394        return splitByCharacterType(str, false);
    7395    }
    7396
    7397    /**
    7398     * <p>Splits a String by Character type as returned by
    7399     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7400     * characters of the same type are returned as complete tokens, with the
    7401     * following exception: if {@code camelCase} is {@code true},
    7402     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
    7403     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
    7404     * will belong to the following token rather than to the preceding, if any,
    7405     * {@code Character.UPPERCASE_LETTER} token.
    7406     * @param str the String to split, may be {@code null}
    7407     * @param camelCase whether to use so-called "camel-case" for letter types
    7408     * @return an array of parsed Strings, {@code null} if null String input
    7409     * @since 2.4
    7410     */
    7411    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
    7412        if (str == null) {
    7413            return null;
    7414        }
    7415        if (str.isEmpty()) {
    7416            return ArrayUtils.EMPTY_STRING_ARRAY;
    7417        }
    7418        final char[] c = str.toCharArray();
    7419        final List<String> list = new ArrayList<>();
    7420        int tokenStart = 0;
    7421        int currentType = Character.getType(c[tokenStart]);
    7422        for (int pos = tokenStart + 1; pos < c.length; pos++) {
    7423            final int type = Character.getType(c[pos]);
    7424            if (type == currentType) {
    7425                continue;
    7426            }
    7427            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    7428                final int newTokenStart = pos - 1;
    7429                if (newTokenStart != tokenStart) {
    7430                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    7431                    tokenStart = newTokenStart;
    7432                }
    7433            } else {
    7434                list.add(new String(c, tokenStart, pos - tokenStart));
    7435                tokenStart = pos;
    7436            }
    7437            currentType = type;
    7438        }
    7439        list.add(new String(c, tokenStart, c.length - tokenStart));
    7440        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7441    }
    7442
    7443    /**
    7444     * <p>Splits a String by Character type as returned by
    7445     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7446     * characters of the same type are returned as complete tokens, with the
    7447     * following exception: the character of type
    7448     * {@code Character.UPPERCASE_LETTER}, if any, immediately
    7449     * preceding a token of type {@code Character.LOWERCASE_LETTER}
    7450     * will belong to the following token rather than to the preceding, if any,
    7451     * {@code Character.UPPERCASE_LETTER} token.
    7452     * <pre>
    7453     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    7454     * StringUtils.splitByCharacterTypeCamelCase("")           = []
    7455     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7456     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7457     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7458     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    7459     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    7460     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    7461     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    7462     * </pre>
    7463     * @param str the String to split, may be {@code null}
    7464     * @return an array of parsed Strings, {@code null} if null String input
    7465     * @since 2.4
    7466     */
    7467    public static String[] splitByCharacterTypeCamelCase(final String str) {
    7468        return splitByCharacterType(str, true);
    7469    }
    7470
    7471    /**
    7472     * <p>Splits the provided text into an array, separator string specified.
    7473     *
    7474     * <p>The separator(s) will not be included in the returned String array.
    7475     * Adjacent separators are treated as one separator.</p>
    7476     *
    7477     * <p>A {@code null} input String returns {@code null}.
    7478     * A {@code null} separator splits on whitespace.</p>
    7479     *
    7480     * <pre>
    7481     * StringUtils.splitByWholeSeparator(null, *)               = null
    7482     * StringUtils.splitByWholeSeparator("", *)                 = []
    7483     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    7484     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    7485     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7486     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7487     * </pre>
    7488     *
    7489     * @param str  the String to parse, may be null
    7490     * @param separator  String containing the String to be used as a delimiter,
    7491     *  {@code null} splits on whitespace
    7492     * @return an array of parsed Strings, {@code null} if null String was input
    7493     */
    7494    public static String[] splitByWholeSeparator(final String str, final String separator) {
    7495        return splitByWholeSeparatorWorker(str, separator, -1, false);
    7496    }
    7497
    7498    /**
    7499     * Splits the provided text into an array, separator string specified.
    7500     * Returns a maximum of {@code max} substrings.
    7501     *
    7502     * <p>The separator(s) will not be included in the returned String array.
    7503     * Adjacent separators are treated as one separator.</p>
    7504     *
    7505     * <p>A {@code null} input String returns {@code null}.
    7506     * A {@code null} separator splits on whitespace.</p>
    7507     *
    7508     * <pre>
    7509     * StringUtils.splitByWholeSeparator(null, *, *)               = null
    7510     * StringUtils.splitByWholeSeparator("", *, *)                 = []
    7511     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7512     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    7513     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7514     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7515     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7516     * </pre>
    7517     *
    7518     * @param str  the String to parse, may be null
    7519     * @param separator  String containing the String to be used as a delimiter,
    7520     *  {@code null} splits on whitespace
    7521     * @param max  the maximum number of elements to include in the returned
    7522     *  array. A zero or negative value implies no limit.
    7523     * @return an array of parsed Strings, {@code null} if null String was input
    7524     */
    7525    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
    7526        return splitByWholeSeparatorWorker(str, separator, max, false);
    7527    }
    7528
    7529    /**
    7530     * Splits the provided text into an array, separator string specified.
    7531     *
    7532     * <p>The separator is not included in the returned String array.
    7533     * Adjacent separators are treated as separators for empty tokens.
    7534     * For more control over the split use the StrTokenizer class.</p>
    7535     *
    7536     * <p>A {@code null} input String returns {@code null}.
    7537     * A {@code null} separator splits on whitespace.</p>
    7538     *
    7539     * <pre>
    7540     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    7541     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    7542     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    7543     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    7544     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7545     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7546     * </pre>
    7547     *
    7548     * @param str  the String to parse, may be null
    7549     * @param separator  String containing the String to be used as a delimiter,
    7550     *  {@code null} splits on whitespace
    7551     * @return an array of parsed Strings, {@code null} if null String was input
    7552     * @since 2.4
    7553     */
    7554    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
    7555        return splitByWholeSeparatorWorker(str, separator, -1, true);
    7556    }
    7557
    7558    /**
    7559     * Splits the provided text into an array, separator string specified.
    7560     * Returns a maximum of {@code max} substrings.
    7561     *
    7562     * <p>The separator is not included in the returned String array.
    7563     * Adjacent separators are treated as separators for empty tokens.
    7564     * For more control over the split use the StrTokenizer class.</p>
    7565     *
    7566     * <p>A {@code null} input String returns {@code null}.
    7567     * A {@code null} separator splits on whitespace.</p>
    7568     *
    7569     * <pre>
    7570     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    7571     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    7572     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7573     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    7574     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7575     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7576     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7577     * </pre>
    7578     *
    7579     * @param str  the String to parse, may be null
    7580     * @param separator  String containing the String to be used as a delimiter,
    7581     *  {@code null} splits on whitespace
    7582     * @param max  the maximum number of elements to include in the returned
    7583     *  array. A zero or negative value implies no limit.
    7584     * @return an array of parsed Strings, {@code null} if null String was input
    7585     * @since 2.4
    7586     */
    7587    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
    7588        return splitByWholeSeparatorWorker(str, separator, max, true);
    7589    }
    7590
    7591    /**
    7592     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
    7593     *
    7594     * @param str  the String to parse, may be {@code null}
    7595     * @param separator  String containing the String to be used as a delimiter,
    7596     *  {@code null} splits on whitespace
    7597     * @param max  the maximum number of elements to include in the returned
    7598     *  array. A zero or negative value implies no limit.
    7599     * @param preserveAllTokens if {@code true}, adjacent separators are
    7600     * treated as empty token separators; if {@code false}, adjacent
    7601     * separators are treated as one separator.
    7602     * @return an array of parsed Strings, {@code null} if null String input
    7603     * @since 2.4
    7604     */
    7605    private static String[] splitByWholeSeparatorWorker(
    7606            final String str, final String separator, final int max, final boolean preserveAllTokens) {
    7607        if (str == null) {
    7608            return null;
    7609        }
    7610
    7611        final int len = str.length();
    7612
    7613        if (len == 0) {
    7614            return ArrayUtils.EMPTY_STRING_ARRAY;
    7615        }
    7616
    7617        if (separator == null || EMPTY.equals(separator)) {
    7618            // Split on whitespace.
    7619            return splitWorker(str, null, max, preserveAllTokens);
    7620        }
    7621
    7622        final int separatorLength = separator.length();
    7623
    7624        final ArrayList<String> substrings = new ArrayList<>();
    7625        int numberOfSubstrings = 0;
    7626        int beg = 0;
    7627        int end = 0;
    7628        while (end < len) {
    7629            end = str.indexOf(separator, beg);
    7630
    7631            if (end > -1) {
    7632                if (end > beg) {
    7633                    numberOfSubstrings += 1;
    7634
    7635                    if (numberOfSubstrings == max) {
    7636                        end = len;
    7637                        substrings.add(str.substring(beg));
    7638                    } else {
    7639                        // The following is OK, because String.substring( beg, end ) excludes
    7640                        // the character at the position 'end'.
    7641                        substrings.add(str.substring(beg, end));
    7642
    7643                        // Set the starting point for the next search.
    7644                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    7645                        // which is the right calculation:
    7646                        beg = end + separatorLength;
    7647                    }
    7648                } else {
    7649                    // We found a consecutive occurrence of the separator, so skip it.
    7650                    if (preserveAllTokens) {
    7651                        numberOfSubstrings += 1;
    7652                        if (numberOfSubstrings == max) {
    7653                            end = len;
    7654                            substrings.add(str.substring(beg));
    7655                        } else {
    7656                            substrings.add(EMPTY);
    7657                        }
    7658                    }
    7659                    beg = end + separatorLength;
    7660                }
    7661            } else {
    7662                // String.substring( beg ) goes from 'beg' to the end of the String.
    7663                substrings.add(str.substring(beg));
    7664                end = len;
    7665            }
    7666        }
    7667
    7668        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7669    }
    7670
    7671    /**
    7672     * Splits the provided text into an array, using whitespace as the
    7673     * separator, preserving all tokens, including empty tokens created by
    7674     * adjacent separators. This is an alternative to using StringTokenizer.
    7675     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7676     *
    7677     * <p>The separator is not included in the returned String array.
    7678     * Adjacent separators are treated as separators for empty tokens.
    7679     * For more control over the split use the StrTokenizer class.</p>
    7680     *
    7681     * <p>A {@code null} input String returns {@code null}.</p>
    7682     *
    7683     * <pre>
    7684     * StringUtils.splitPreserveAllTokens(null)       = null
    7685     * StringUtils.splitPreserveAllTokens("")         = []
    7686     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    7687     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    7688     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    7689     * </pre>
    7690     *
    7691     * @param str  the String to parse, may be {@code null}
    7692     * @return an array of parsed Strings, {@code null} if null String input
    7693     * @since 2.1
    7694     */
    7695    public static String[] splitPreserveAllTokens(final String str) {
    7696        return splitWorker(str, null, -1, true);
    7697    }
    7698
    7699    /**
    7700     * Splits the provided text into an array, separator specified,
    7701     * preserving all tokens, including empty tokens created by adjacent
    7702     * separators. This is an alternative to using StringTokenizer.
    7703     *
    7704     * <p>The separator is not included in the returned String array.
    7705     * Adjacent separators are treated as separators for empty tokens.
    7706     * For more control over the split use the StrTokenizer class.</p>
    7707     *
    7708     * <p>A {@code null} input String returns {@code null}.</p>
    7709     *
    7710     * <pre>
    7711     * StringUtils.splitPreserveAllTokens(null, *)         = null
    7712     * StringUtils.splitPreserveAllTokens("", *)           = []
    7713     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    7714     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    7715     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    7716     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    7717     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    7718     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    7719     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
    7720     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
    7721     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
    7722     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
    7723     * </pre>
    7724     *
    7725     * @param str  the String to parse, may be {@code null}
    7726     * @param separatorChar  the character used as the delimiter,
    7727     *  {@code null} splits on whitespace
    7728     * @return an array of parsed Strings, {@code null} if null String input
    7729     * @since 2.1
    7730     */
    7731    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
    7732        return splitWorker(str, separatorChar, true);
    7733    }
    7734
    7735    /**
    7736     * Splits the provided text into an array, separators specified,
    7737     * preserving all tokens, including empty tokens created by adjacent
    7738     * separators. This is an alternative to using StringTokenizer.
    7739     *
    7740     * <p>The separator is not included in the returned String array.
    7741     * Adjacent separators are treated as separators for empty tokens.
    7742     * For more control over the split use the StrTokenizer class.</p>
    7743     *
    7744     * <p>A {@code null} input String returns {@code null}.
    7745     * A {@code null} separatorChars splits on whitespace.</p>
    7746     *
    7747     * <pre>
    7748     * StringUtils.splitPreserveAllTokens(null, *)           = null
    7749     * StringUtils.splitPreserveAllTokens("", *)             = []
    7750     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    7751     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    7752     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
    7753     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    7754     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    7755     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    7756     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
    7757     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
    7758     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
    7759     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
    7760     * </pre>
    7761     *
    7762     * @param str  the String to parse, may be {@code null}
    7763     * @param separatorChars  the characters used as the delimiters,
    7764     *  {@code null} splits on whitespace
    7765     * @return an array of parsed Strings, {@code null} if null String input
    7766     * @since 2.1
    7767     */
    7768    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
    7769        return splitWorker(str, separatorChars, -1, true);
    7770    }
    7771
    7772    /**
    7773     * Splits the provided text into an array with a maximum length,
    7774     * separators specified, preserving all tokens, including empty tokens
    7775     * created by adjacent separators.
    7776     *
    7777     * <p>The separator is not included in the returned String array.
    7778     * Adjacent separators are treated as separators for empty tokens.
    7779     * Adjacent separators are treated as one separator.</p>
    7780     *
    7781     * <p>A {@code null} input String returns {@code null}.
    7782     * A {@code null} separatorChars splits on whitespace.</p>
    7783     *
    7784     * <p>If more than {@code max} delimited substrings are found, the last
    7785     * returned string includes all characters after the first {@code max - 1}
    7786     * returned strings (including separator characters).</p>
    7787     *
    7788     * <pre>
    7789     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    7790     * StringUtils.splitPreserveAllTokens("", *, *)              = []
    7791     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
    7792     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
    7793     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7794     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7795     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    7796     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    7797     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    7798     * </pre>
    7799     *
    7800     * @param str  the String to parse, may be {@code null}
    7801     * @param separatorChars  the characters used as the delimiters,
    7802     *  {@code null} splits on whitespace
    7803     * @param max  the maximum number of elements to include in the
    7804     *  array. A zero or negative value implies no limit
    7805     * @return an array of parsed Strings, {@code null} if null String input
    7806     * @since 2.1
    7807     */
    7808    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
    7809        return splitWorker(str, separatorChars, max, true);
    7810    }
    7811
    7812    /**
    7813     * Performs the logic for the {@code split} and
    7814     * {@code splitPreserveAllTokens} methods that do not return a
    7815     * maximum array length.
    7816     *
    7817     * @param str  the String to parse, may be {@code null}
    7818     * @param separatorChar the separate character
    7819     * @param preserveAllTokens if {@code true}, adjacent separators are
    7820     * treated as empty token separators; if {@code false}, adjacent
    7821     * separators are treated as one separator.
    7822     * @return an array of parsed Strings, {@code null} if null String input
    7823     */
    7824    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
    7825        // Performance tuned for 2.0 (JDK1.4)
    7826
    7827        if (str == null) {
    7828            return null;
    7829        }
    7830        final int len = str.length();
    7831        if (len == 0) {
    7832            return ArrayUtils.EMPTY_STRING_ARRAY;
    7833        }
    7834        final List<String> list = new ArrayList<>();
    7835        int i = 0;
    7836        int start = 0;
    7837        boolean match = false;
    7838        boolean lastMatch = false;
    7839        while (i < len) {
    7840            if (str.charAt(i) == separatorChar) {
    7841                if (match || preserveAllTokens) {
    7842                    list.add(str.substring(start, i));
    7843                    match = false;
    7844                    lastMatch = true;
    7845                }
    7846                start = ++i;
    7847                continue;
    7848            }
    7849            lastMatch = false;
    7850            match = true;
    7851            i++;
    7852        }
    7853        if (match || preserveAllTokens && lastMatch) {
    7854            list.add(str.substring(start, i));
    7855        }
    7856        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7857    }
    7858
    7859    /**
    7860     * Performs the logic for the {@code split} and
    7861     * {@code splitPreserveAllTokens} methods that return a maximum array
    7862     * length.
    7863     *
    7864     * @param str  the String to parse, may be {@code null}
    7865     * @param separatorChars the separate character
    7866     * @param max  the maximum number of elements to include in the
    7867     *  array. A zero or negative value implies no limit.
    7868     * @param preserveAllTokens if {@code true}, adjacent separators are
    7869     * treated as empty token separators; if {@code false}, adjacent
    7870     * separators are treated as one separator.
    7871     * @return an array of parsed Strings, {@code null} if null String input
    7872     */
    7873    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
    7874        // Performance tuned for 2.0 (JDK1.4)
    7875        // Direct code is quicker than StringTokenizer.
    7876        // Also, StringTokenizer uses isSpace() not isWhitespace()
    7877
    7878        if (str == null) {
    7879            return null;
    7880        }
    7881        final int len = str.length();
    7882        if (len == 0) {
    7883            return ArrayUtils.EMPTY_STRING_ARRAY;
    7884        }
    7885        final List<String> list = new ArrayList<>();
    7886        int sizePlus1 = 1;
    7887        int i = 0;
    7888        int start = 0;
    7889        boolean match = false;
    7890        boolean lastMatch = false;
    7891        if (separatorChars == null) {
    7892            // Null separator means use whitespace
    7893            while (i < len) {
    7894                if (Character.isWhitespace(str.charAt(i))) {
    7895                    if (match || preserveAllTokens) {
    7896                        lastMatch = true;
    7897                        if (sizePlus1++ == max) {
    7898                            i = len;
    7899                            lastMatch = false;
    7900                        }
    7901                        list.add(str.substring(start, i));
    7902                        match = false;
    7903                    }
    7904                    start = ++i;
    7905                    continue;
    7906                }
    7907                lastMatch = false;
    7908                match = true;
    7909                i++;
    7910            }
    7911        } else if (separatorChars.length() == 1) {
    7912            // Optimise 1 character case
    7913            final char sep = separatorChars.charAt(0);
    7914            while (i < len) {
    7915                if (str.charAt(i) == sep) {
    7916                    if (match || preserveAllTokens) {
    7917                        lastMatch = true;
    7918                        if (sizePlus1++ == max) {
    7919                            i = len;
    7920                            lastMatch = false;
    7921                        }
    7922                        list.add(str.substring(start, i));
    7923                        match = false;
    7924                    }
    7925                    start = ++i;
    7926                    continue;
    7927                }
    7928                lastMatch = false;
    7929                match = true;
    7930                i++;
    7931            }
    7932        } else {
    7933            // standard case
    7934            while (i < len) {
    7935                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    7936                    if (match || preserveAllTokens) {
    7937                        lastMatch = true;
    7938                        if (sizePlus1++ == max) {
    7939                            i = len;
    7940                            lastMatch = false;
    7941                        }
    7942                        list.add(str.substring(start, i));
    7943                        match = false;
    7944                    }
    7945                    start = ++i;
    7946                    continue;
    7947                }
    7948                lastMatch = false;
    7949                match = true;
    7950                i++;
    7951            }
    7952        }
    7953        if (match || preserveAllTokens && lastMatch) {
    7954            list.add(str.substring(start, i));
    7955        }
    7956        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7957    }
    7958
    7959    /**
    7960     * Check if a CharSequence starts with a specified prefix.
    7961     *
    7962     * <p>{@code null}s are handled without exceptions. Two {@code null}
    7963     * references are considered to be equal. The comparison is case-sensitive.</p>
    7964     *
    7965     * <pre>
    7966     * StringUtils.startsWith(null, null)      = true
    7967     * StringUtils.startsWith(null, "abc")     = false
    7968     * StringUtils.startsWith("abcdef", null)  = false
    7969     * StringUtils.startsWith("abcdef", "abc") = true
    7970     * StringUtils.startsWith("ABCDEF", "abc") = false
    7971     * </pre>
    7972     *
    7973     * @see String#startsWith(String)
    7974     * @param str  the CharSequence to check, may be null
    7975     * @param prefix the prefix to find, may be null
    7976     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
    7977     *  both {@code null}
    7978     * @since 2.4
    7979     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
    7980     */
    7981    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
    7982        return startsWith(str, prefix, false);
    7983    }
    7984
    7985    /**
    7986     * Check if a CharSequence starts with a specified prefix (optionally case insensitive).
    7987     *
    7988     * @see String#startsWith(String)
    7989     * @param str  the CharSequence to check, may be null
    7990     * @param prefix the prefix to find, may be null
    7991     * @param ignoreCase indicates whether the compare should ignore case
    7992     *  (case-insensitive) or not.
    7993     * @return {@code true} if the CharSequence starts with the prefix or
    7994     *  both {@code null}
    7995     */
    7996    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
    7997        if (str == null || prefix == null) {
    7998            return str == prefix;
    7999        }
    8000        // Get length once instead of twice in the unlikely case that it changes.
    8001        final int preLen = prefix.length();
    8002        if (preLen > str.length()) {
    8003            return false;
    8004        }
    8005        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen);
    8006    }
    8007
    8008    /**
    8009     * Check if a CharSequence starts with any of the provided case-sensitive prefixes.
    8010     *
    8011     * <pre>
    8012     * StringUtils.startsWithAny(null, null)      = false
    8013     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    8014     * StringUtils.startsWithAny("abcxyz", null)     = false
    8015     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
    8016     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    8017     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    8018     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
    8019     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
    8020     * </pre>
    8021     *
    8022     * @param sequence the CharSequence to check, may be null
    8023     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
    8024     * @see StringUtils#startsWith(CharSequence, CharSequence)
    8025     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    8026     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
    8027     * @since 2.5
    8028     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
    8029     */
    8030    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    8031        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    8032            return false;
    8033        }
    8034        for (final CharSequence searchString : searchStrings) {
    8035            if (startsWith(sequence, searchString)) {
    8036                return true;
    8037            }
    8038        }
    8039        return false;
    8040    }
    8041
    8042    /**
    8043     * Case insensitive check if a CharSequence starts with a specified prefix.
    8044     *
    8045     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8046     * references are considered to be equal. The comparison is case insensitive.</p>
    8047     *
    8048     * <pre>
    8049     * StringUtils.startsWithIgnoreCase(null, null)      = true
    8050     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    8051     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    8052     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    8053     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    8054     * </pre>
    8055     *
    8056     * @see String#startsWith(String)
    8057     * @param str  the CharSequence to check, may be null
    8058     * @param prefix the prefix to find, may be null
    8059     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
    8060     *  both {@code null}
    8061     * @since 2.4
    8062     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
    8063     */
    8064    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
    8065        return startsWith(str, prefix, true);
    8066    }
    8067
    8068    /**
    8069     * Strips whitespace from the start and end of a String.
    8070     *
    8071     * <p>This is similar to {@link #trim(String)} but removes whitespace.
    8072     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8073     *
    8074     * <p>A {@code null} input String returns {@code null}.</p>
    8075     *
    8076     * <pre>
    8077     * StringUtils.strip(null)     = null
    8078     * StringUtils.strip("")       = ""
    8079     * StringUtils.strip("   ")    = ""
    8080     * StringUtils.strip("abc")    = "abc"
    8081     * StringUtils.strip("  abc")  = "abc"
    8082     * StringUtils.strip("abc  ")  = "abc"
    8083     * StringUtils.strip(" abc ")  = "abc"
    8084     * StringUtils.strip(" ab c ") = "ab c"
    8085     * </pre>
    8086     *
    8087     * @param str  the String to remove whitespace from, may be null
    8088     * @return the stripped String, {@code null} if null String input
    8089     */
    8090    public static String strip(final String str) {
    8091        return strip(str, null);
    8092    }
    8093
    8094    /**
    8095     * Strips any of a set of characters from the start and end of a String.
    8096     * This is similar to {@link String#trim()} but allows the characters
    8097     * to be stripped to be controlled.
    8098     *
    8099     * <p>A {@code null} input String returns {@code null}.
    8100     * An empty string ("") input returns the empty string.</p>
    8101     *
    8102     * <p>If the stripChars String is {@code null}, whitespace is
    8103     * stripped as defined by {@link Character#isWhitespace(char)}.
    8104     * Alternatively use {@link #strip(String)}.</p>
    8105     *
    8106     * <pre>
    8107     * StringUtils.strip(null, *)          = null
    8108     * StringUtils.strip("", *)            = ""
    8109     * StringUtils.strip("abc", null)      = "abc"
    8110     * StringUtils.strip("  abc", null)    = "abc"
    8111     * StringUtils.strip("abc  ", null)    = "abc"
    8112     * StringUtils.strip(" abc ", null)    = "abc"
    8113     * StringUtils.strip("  abcyx", "xyz") = "  abc"
    8114     * </pre>
    8115     *
    8116     * @param str  the String to remove characters from, may be null
    8117     * @param stripChars  the characters to remove, null treated as whitespace
    8118     * @return the stripped String, {@code null} if null String input
    8119     */
    8120    public static String strip(String str, final String stripChars) {
    8121        str = stripStart(str, stripChars);
    8122        return stripEnd(str, stripChars);
    8123    }
    8124
    8125    /**
    8126     * Removes diacritics (~= accents) from a string. The case will not be altered.
    8127     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
    8128     * <p>Note that ligatures will be left as is.</p>
    8129     *
    8130     * <pre>
    8131     * StringUtils.stripAccents(null)                = null
    8132     * StringUtils.stripAccents("")                  = ""
    8133     * StringUtils.stripAccents("control")           = "control"
    8134     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
    8135     * </pre>
    8136     *
    8137     * @param input String to be stripped
    8138     * @return input text with diacritics removed
    8139     *
    8140     * @since 3.0
    8141     */
    8142    // 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).
    8143    public static String stripAccents(final String input) {
    8144        if (input == null) {
    8145            return null;
    8146        }
    8147        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
    8148        convertRemainingAccentCharacters(decomposed);
    8149        // Note that this doesn't correctly remove ligatures...
    8150        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
    8151    }
    8152
    8153    /**
    8154     * Strips whitespace from the start and end of every String in an array.
    8155     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    8156     *
    8157     * <p>A new array is returned each time, except for length zero.
    8158     * A {@code null} array will return {@code null}.
    8159     * An empty array will return itself.
    8160     * A {@code null} array entry will be ignored.</p>
    8161     *
    8162     * <pre>
    8163     * StringUtils.stripAll(null)             = null
    8164     * StringUtils.stripAll([])               = []
    8165     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    8166     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    8167     * </pre>
    8168     *
    8169     * @param strs  the array to remove whitespace from, may be null
    8170     * @return the stripped Strings, {@code null} if null array input
    8171     */
    8172    public static String[] stripAll(final String... strs) {
    8173        return stripAll(strs, null);
    8174    }
    8175
    8176    /**
    8177     * Strips any of a set of characters from the start and end of every
    8178     * String in an array.
    8179     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8180     *
    8181     * <p>A new array is returned each time, except for length zero.
    8182     * A {@code null} array will return {@code null}.
    8183     * An empty array will return itself.
    8184     * A {@code null} array entry will be ignored.
    8185     * A {@code null} stripChars will strip whitespace as defined by
    8186     * {@link Character#isWhitespace(char)}.</p>
    8187     *
    8188     * <pre>
    8189     * StringUtils.stripAll(null, *)                = null
    8190     * StringUtils.stripAll([], *)                  = []
    8191     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    8192     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    8193     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    8194     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    8195     * </pre>
    8196     *
    8197     * @param strs  the array to remove characters from, may be null
    8198     * @param stripChars  the characters to remove, null treated as whitespace
    8199     * @return the stripped Strings, {@code null} if null array input
    8200     */
    8201    public static String[] stripAll(final String[] strs, final String stripChars) {
    8202        final int strsLen = ArrayUtils.getLength(strs);
    8203        if (strsLen == 0) {
    8204            return strs;
    8205        }
    8206        final String[] newArr = new String[strsLen];
    8207        Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
    8208        return newArr;
    8209    }
    8210
    8211    /**
    8212     * Strips any of a set of characters from the end of a String.
    8213     *
    8214     * <p>A {@code null} input String returns {@code null}.
    8215     * An empty string ("") input returns the empty string.</p>
    8216     *
    8217     * <p>If the stripChars String is {@code null}, whitespace is
    8218     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8219     *
    8220     * <pre>
    8221     * StringUtils.stripEnd(null, *)          = null
    8222     * StringUtils.stripEnd("", *)            = ""
    8223     * StringUtils.stripEnd("abc", "")        = "abc"
    8224     * StringUtils.stripEnd("abc", null)      = "abc"
    8225     * StringUtils.stripEnd("  abc", null)    = "  abc"
    8226     * StringUtils.stripEnd("abc  ", null)    = "abc"
    8227     * StringUtils.stripEnd(" abc ", null)    = " abc"
    8228     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    8229     * StringUtils.stripEnd("120.00", ".0")   = "12"
    8230     * </pre>
    8231     *
    8232     * @param str  the String to remove characters from, may be null
    8233     * @param stripChars  the set of characters to remove, null treated as whitespace
    8234     * @return the stripped String, {@code null} if null String input
    8235     */
    8236    public static String stripEnd(final String str, final String stripChars) {
    8237        int end = length(str);
    8238        if (end == 0) {
    8239            return str;
    8240        }
    8241
    8242        if (stripChars == null) {
    8243            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
    8244                end--;
    8245            }
    8246        } else if (stripChars.isEmpty()) {
    8247            return str;
    8248        } else {
    8249            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
    8250                end--;
    8251            }
    8252        }
    8253        return str.substring(0, end);
    8254    }
    8255
    8256    /**
    8257     * Strips any of a set of characters from the start of a String.
    8258     *
    8259     * <p>A {@code null} input String returns {@code null}.
    8260     * An empty string ("") input returns the empty string.</p>
    8261     *
    8262     * <p>If the stripChars String is {@code null}, whitespace is
    8263     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8264     *
    8265     * <pre>
    8266     * StringUtils.stripStart(null, *)          = null
    8267     * StringUtils.stripStart("", *)            = ""
    8268     * StringUtils.stripStart("abc", "")        = "abc"
    8269     * StringUtils.stripStart("abc", null)      = "abc"
    8270     * StringUtils.stripStart("  abc", null)    = "abc"
    8271     * StringUtils.stripStart("abc  ", null)    = "abc  "
    8272     * StringUtils.stripStart(" abc ", null)    = "abc "
    8273     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    8274     * </pre>
    8275     *
    8276     * @param str  the String to remove characters from, may be null
    8277     * @param stripChars  the characters to remove, null treated as whitespace
    8278     * @return the stripped String, {@code null} if null String input
    8279     */
    8280    public static String stripStart(final String str, final String stripChars) {
    8281        final int strLen = length(str);
    8282        if (strLen == 0) {
    8283            return str;
    8284        }
    8285        int start = 0;
    8286        if (stripChars == null) {
    8287            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
    8288                start++;
    8289            }
    8290        } else if (stripChars.isEmpty()) {
    8291            return str;
    8292        } else {
    8293            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
    8294                start++;
    8295            }
    8296        }
    8297        return str.substring(start);
    8298    }
    8299
    8300    /**
    8301     * Strips whitespace from the start and end of a String  returning
    8302     * an empty String if {@code null} input.
    8303     *
    8304     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
    8305     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8306     *
    8307     * <pre>
    8308     * StringUtils.stripToEmpty(null)     = ""
    8309     * StringUtils.stripToEmpty("")       = ""
    8310     * StringUtils.stripToEmpty("   ")    = ""
    8311     * StringUtils.stripToEmpty("abc")    = "abc"
    8312     * StringUtils.stripToEmpty("  abc")  = "abc"
    8313     * StringUtils.stripToEmpty("abc  ")  = "abc"
    8314     * StringUtils.stripToEmpty(" abc ")  = "abc"
    8315     * StringUtils.stripToEmpty(" ab c ") = "ab c"
    8316     * </pre>
    8317     *
    8318     * @param str  the String to be stripped, may be null
    8319     * @return the trimmed String, or an empty String if {@code null} input
    8320     * @since 2.0
    8321     */
    8322    public static String stripToEmpty(final String str) {
    8323        return str == null ? EMPTY : strip(str, null);
    8324    }
    8325
    8326    /**
    8327     * Strips whitespace from the start and end of a String  returning
    8328     * {@code null} if the String is empty ("") after the strip.
    8329     *
    8330     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
    8331     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8332     *
    8333     * <pre>
    8334     * StringUtils.stripToNull(null)     = null
    8335     * StringUtils.stripToNull("")       = null
    8336     * StringUtils.stripToNull("   ")    = null
    8337     * StringUtils.stripToNull("abc")    = "abc"
    8338     * StringUtils.stripToNull("  abc")  = "abc"
    8339     * StringUtils.stripToNull("abc  ")  = "abc"
    8340     * StringUtils.stripToNull(" abc ")  = "abc"
    8341     * StringUtils.stripToNull(" ab c ") = "ab c"
    8342     * </pre>
    8343     *
    8344     * @param str  the String to be stripped, may be null
    8345     * @return the stripped String,
    8346     *  {@code null} if whitespace, empty or null String input
    8347     * @since 2.0
    8348     */
    8349    public static String stripToNull(String str) {
    8350        if (str == null) {
    8351            return null;
    8352        }
    8353        str = strip(str, null);
    8354        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
    8355    }
    8356
    8357    /**
    8358     * Gets a substring from the specified String avoiding exceptions.
    8359     *
    8360     * <p>A negative start position can be used to start {@code n}
    8361     * characters from the end of the String.</p>
    8362     *
    8363     * <p>A {@code null} String will return {@code null}.
    8364     * An empty ("") String will return "".</p>
    8365     *
    8366     * <pre>
    8367     * StringUtils.substring(null, *)   = null
    8368     * StringUtils.substring("", *)     = ""
    8369     * StringUtils.substring("abc", 0)  = "abc"
    8370     * StringUtils.substring("abc", 2)  = "c"
    8371     * StringUtils.substring("abc", 4)  = ""
    8372     * StringUtils.substring("abc", -2) = "bc"
    8373     * StringUtils.substring("abc", -4) = "abc"
    8374     * </pre>
    8375     *
    8376     * @param str  the String to get the substring from, may be null
    8377     * @param start  the position to start from, negative means
    8378     *  count back from the end of the String by this many characters
    8379     * @return substring from start position, {@code null} if null String input
    8380     */
    8381    public static String substring(final String str, int start) {
    8382        if (str == null) {
    8383            return null;
    8384        }
    8385
    8386        // handle negatives, which means last n characters
    8387        if (start < 0) {
    8388            start = str.length() + start; // remember start is negative
    8389        }
    8390
    8391        if (start < 0) {
    8392            start = 0;
    8393        }
    8394        if (start > str.length()) {
    8395            return EMPTY;
    8396        }
    8397
    8398        return str.substring(start);
    8399    }
    8400
    8401    /**
    8402     * Gets a substring from the specified String avoiding exceptions.
    8403     *
    8404     * <p>A negative start position can be used to start/end {@code n}
    8405     * characters from the end of the String.</p>
    8406     *
    8407     * <p>The returned substring starts with the character in the {@code start}
    8408     * position and ends before the {@code end} position. All position counting is
    8409     * zero-based -- i.e., to start at the beginning of the string use
    8410     * {@code start = 0}. Negative start and end positions can be used to
    8411     * specify offsets relative to the end of the String.</p>
    8412     *
    8413     * <p>If {@code start} is not strictly to the left of {@code end}, ""
    8414     * is returned.</p>
    8415     *
    8416     * <pre>
    8417     * StringUtils.substring(null, *, *)    = null
    8418     * StringUtils.substring("", * ,  *)    = "";
    8419     * StringUtils.substring("abc", 0, 2)   = "ab"
    8420     * StringUtils.substring("abc", 2, 0)   = ""
    8421     * StringUtils.substring("abc", 2, 4)   = "c"
    8422     * StringUtils.substring("abc", 4, 6)   = ""
    8423     * StringUtils.substring("abc", 2, 2)   = ""
    8424     * StringUtils.substring("abc", -2, -1) = "b"
    8425     * StringUtils.substring("abc", -4, 2)  = "ab"
    8426     * </pre>
    8427     *
    8428     * @param str  the String to get the substring from, may be null
    8429     * @param start  the position to start from, negative means
    8430     *  count back from the end of the String by this many characters
    8431     * @param end  the position to end at (exclusive), negative means
    8432     *  count back from the end of the String by this many characters
    8433     * @return substring from start position to end position,
    8434     *  {@code null} if null String input
    8435     */
    8436    public static String substring(final String str, int start, int end) {
    8437        if (str == null) {
    8438            return null;
    8439        }
    8440
    8441        // handle negatives
    8442        if (end < 0) {
    8443            end = str.length() + end; // remember end is negative
    8444        }
    8445        if (start < 0) {
    8446            start = str.length() + start; // remember start is negative
    8447        }
    8448
    8449        // check length next
    8450        if (end > str.length()) {
    8451            end = str.length();
    8452        }
    8453
    8454        // if start is greater than end, return ""
    8455        if (start > end) {
    8456            return EMPTY;
    8457        }
    8458
    8459        if (start < 0) {
    8460            start = 0;
    8461        }
    8462        if (end < 0) {
    8463            end = 0;
    8464        }
    8465
    8466        return str.substring(start, end);
    8467    }
    8468
    8469    /**
    8470     * Gets the substring after the first occurrence of a separator.
    8471     * The separator is not returned.
    8472     *
    8473     * <p>A {@code null} string input will return {@code null}.
    8474     * An empty ("") string input will return the empty string.
    8475     *
    8476     * <p>If nothing is found, the empty string is returned.</p>
    8477     *
    8478     * <pre>
    8479     * StringUtils.substringAfter(null, *)      = null
    8480     * StringUtils.substringAfter("", *)        = ""
    8481     * StringUtils.substringAfter("abc", 'a')   = "bc"
    8482     * StringUtils.substringAfter("abcba", 'b') = "cba"
    8483     * StringUtils.substringAfter("abc", 'c')   = ""
    8484     * StringUtils.substringAfter("abc", 'd')   = ""
    8485     * StringUtils.substringAfter(" abc", 32)   = "abc"
    8486     * </pre>
    8487     *
    8488     * @param str  the String to get a substring from, may be null
    8489     * @param separator  the character (Unicode code point) to search.
    8490     * @return the substring after the first occurrence of the separator,
    8491     *  {@code null} if null String input
    8492     * @since 3.11
    8493     */
    8494    public static String substringAfter(final String str, final int separator) {
    8495        if (isEmpty(str)) {
    8496            return str;
    8497        }
    8498        final int pos = str.indexOf(separator);
    8499        if (pos == INDEX_NOT_FOUND) {
    8500            return EMPTY;
    8501        }
    8502        return str.substring(pos + 1);
    8503    }
    8504
    8505    /**
    8506     * Gets the substring after the first occurrence of a separator.
    8507     * The separator is not returned.
    8508     *
    8509     * <p>A {@code null} string input will return {@code null}.
    8510     * An empty ("") string input will return the empty string.
    8511     * A {@code null} separator will return the empty string if the
    8512     * input string is not {@code null}.</p>
    8513     *
    8514     * <p>If nothing is found, the empty string is returned.</p>
    8515     *
    8516     * <pre>
    8517     * StringUtils.substringAfter(null, *)      = null
    8518     * StringUtils.substringAfter("", *)        = ""
    8519     * StringUtils.substringAfter(*, null)      = ""
    8520     * StringUtils.substringAfter("abc", "a")   = "bc"
    8521     * StringUtils.substringAfter("abcba", "b") = "cba"
    8522     * StringUtils.substringAfter("abc", "c")   = ""
    8523     * StringUtils.substringAfter("abc", "d")   = ""
    8524     * StringUtils.substringAfter("abc", "")    = "abc"
    8525     * </pre>
    8526     *
    8527     * @param str  the String to get a substring from, may be null
    8528     * @param separator  the String to search for, may be null
    8529     * @return the substring after the first occurrence of the separator,
    8530     *  {@code null} if null String input
    8531     * @since 2.0
    8532     */
    8533    public static String substringAfter(final String str, final String separator) {
    8534        if (isEmpty(str)) {
    8535            return str;
    8536        }
    8537        if (separator == null) {
    8538            return EMPTY;
    8539        }
    8540        final int pos = str.indexOf(separator);
    8541        if (pos == INDEX_NOT_FOUND) {
    8542            return EMPTY;
    8543        }
    8544        return str.substring(pos + separator.length());
    8545    }
    8546
    8547    /**
    8548     * Gets the substring after the last occurrence of a separator.
    8549     * The separator is not returned.
    8550     *
    8551     * <p>A {@code null} string input will return {@code null}.
    8552     * An empty ("") string input will return the empty string.
    8553     *
    8554     * <p>If nothing is found, the empty string is returned.</p>
    8555     *
    8556     * <pre>
    8557     * StringUtils.substringAfterLast(null, *)      = null
    8558     * StringUtils.substringAfterLast("", *)        = ""
    8559     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
    8560     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
    8561     * StringUtils.substringAfterLast("abcba", 'b') = "a"
    8562     * StringUtils.substringAfterLast("abc", 'c')   = ""
    8563     * StringUtils.substringAfterLast("a", 'a')     = ""
    8564     * StringUtils.substringAfterLast("a", 'z')     = ""
    8565     * </pre>
    8566     *
    8567     * @param str  the String to get a substring from, may be null
    8568     * @param separator  the character (Unicode code point) to search.
    8569     * @return the substring after the last occurrence of the separator,
    8570     *  {@code null} if null String input
    8571     * @since 3.11
    8572     */
    8573    public static String substringAfterLast(final String str, final int separator) {
    8574        if (isEmpty(str)) {
    8575            return str;
    8576        }
    8577        final int pos = str.lastIndexOf(separator);
    8578        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
    8579            return EMPTY;
    8580        }
    8581        return str.substring(pos + 1);
    8582    }
    8583
    8584    /**
    8585     * Gets the substring after the last occurrence of a separator.
    8586     * The separator is not returned.
    8587     *
    8588     * <p>A {@code null} string input will return {@code null}.
    8589     * An empty ("") string input will return the empty string.
    8590     * An empty or {@code null} separator will return the empty string if
    8591     * the input string is not {@code null}.</p>
    8592     *
    8593     * <p>If nothing is found, the empty string is returned.</p>
    8594     *
    8595     * <pre>
    8596     * StringUtils.substringAfterLast(null, *)      = null
    8597     * StringUtils.substringAfterLast("", *)        = ""
    8598     * StringUtils.substringAfterLast(*, "")        = ""
    8599     * StringUtils.substringAfterLast(*, null)      = ""
    8600     * StringUtils.substringAfterLast("abc", "a")   = "bc"
    8601     * StringUtils.substringAfterLast("abcba", "b") = "a"
    8602     * StringUtils.substringAfterLast("abc", "c")   = ""
    8603     * StringUtils.substringAfterLast("a", "a")     = ""
    8604     * StringUtils.substringAfterLast("a", "z")     = ""
    8605     * </pre>
    8606     *
    8607     * @param str  the String to get a substring from, may be null
    8608     * @param separator  the String to search for, may be null
    8609     * @return the substring after the last occurrence of the separator,
    8610     *  {@code null} if null String input
    8611     * @since 2.0
    8612     */
    8613    public static String substringAfterLast(final String str, final String separator) {
    8614        if (isEmpty(str)) {
    8615            return str;
    8616        }
    8617        if (isEmpty(separator)) {
    8618            return EMPTY;
    8619        }
    8620        final int pos = str.lastIndexOf(separator);
    8621        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
    8622            return EMPTY;
    8623        }
    8624        return str.substring(pos + separator.length());
    8625    }
    8626
    8627    /**
    8628     * Gets the substring before the first occurrence of a separator. The separator is not returned.
    8629     *
    8630     * <p>
    8631     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8632     * </p>
    8633     *
    8634     * <p>
    8635     * If nothing is found, the string input is returned.
    8636     * </p>
    8637     *
    8638     * <pre>
    8639     * StringUtils.substringBefore(null, *)      = null
    8640     * StringUtils.substringBefore("", *)        = ""
    8641     * StringUtils.substringBefore("abc", 'a')   = ""
    8642     * StringUtils.substringBefore("abcba", 'b') = "a"
    8643     * StringUtils.substringBefore("abc", 'c')   = "ab"
    8644     * StringUtils.substringBefore("abc", 'd')   = "abc"
    8645     * </pre>
    8646     *
    8647     * @param str the String to get a substring from, may be null
    8648     * @param separator the character (Unicode code point) to search.
    8649     * @return the substring before the first occurrence of the separator, {@code null} if null String input
    8650     * @since 3.12.0
    8651     */
    8652    public static String substringBefore(final String str, final int separator) {
    8653        if (isEmpty(str)) {
    8654            return str;
    8655        }
    8656        final int pos = str.indexOf(separator);
    8657        if (pos == INDEX_NOT_FOUND) {
    8658            return str;
    8659        }
    8660        return str.substring(0, pos);
    8661    }
    8662
    8663    /**
    8664     * Gets the substring before the first occurrence of a separator.
    8665     * The separator is not returned.
    8666     *
    8667     * <p>A {@code null} string input will return {@code null}.
    8668     * An empty ("") string input will return the empty string.
    8669     * A {@code null} separator will return the input string.</p>
    8670     *
    8671     * <p>If nothing is found, the string input is returned.</p>
    8672     *
    8673     * <pre>
    8674     * StringUtils.substringBefore(null, *)      = null
    8675     * StringUtils.substringBefore("", *)        = ""
    8676     * StringUtils.substringBefore("abc", "a")   = ""
    8677     * StringUtils.substringBefore("abcba", "b") = "a"
    8678     * StringUtils.substringBefore("abc", "c")   = "ab"
    8679     * StringUtils.substringBefore("abc", "d")   = "abc"
    8680     * StringUtils.substringBefore("abc", "")    = ""
    8681     * StringUtils.substringBefore("abc", null)  = "abc"
    8682     * </pre>
    8683     *
    8684     * @param str  the String to get a substring from, may be null
    8685     * @param separator  the String to search for, may be null
    8686     * @return the substring before the first occurrence of the separator,
    8687     *  {@code null} if null String input
    8688     * @since 2.0
    8689     */
    8690    public static String substringBefore(final String str, final String separator) {
    8691        if (isEmpty(str) || separator == null) {
    8692            return str;
    8693        }
    8694        if (separator.isEmpty()) {
    8695            return EMPTY;
    8696        }
    8697        final int pos = str.indexOf(separator);
    8698        if (pos == INDEX_NOT_FOUND) {
    8699            return str;
    8700        }
    8701        return str.substring(0, pos);
    8702    }
    8703
    8704    /**
    8705     * Gets the substring before the last occurrence of a separator.
    8706     * The separator is not returned.
    8707     *
    8708     * <p>A {@code null} string input will return {@code null}.
    8709     * An empty ("") string input will return the empty string.
    8710     * An empty or {@code null} separator will return the input string.</p>
    8711     *
    8712     * <p>If nothing is found, the string input is returned.</p>
    8713     *
    8714     * <pre>
    8715     * StringUtils.substringBeforeLast(null, *)      = null
    8716     * StringUtils.substringBeforeLast("", *)        = ""
    8717     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    8718     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    8719     * StringUtils.substringBeforeLast("a", "a")     = ""
    8720     * StringUtils.substringBeforeLast("a", "z")     = "a"
    8721     * StringUtils.substringBeforeLast("a", null)    = "a"
    8722     * StringUtils.substringBeforeLast("a", "")      = "a"
    8723     * </pre>
    8724     *
    8725     * @param str  the String to get a substring from, may be null
    8726     * @param separator  the String to search for, may be null
    8727     * @return the substring before the last occurrence of the separator,
    8728     *  {@code null} if null String input
    8729     * @since 2.0
    8730     */
    8731    public static String substringBeforeLast(final String str, final String separator) {
    8732        if (isEmpty(str) || isEmpty(separator)) {
    8733            return str;
    8734        }
    8735        final int pos = str.lastIndexOf(separator);
    8736        if (pos == INDEX_NOT_FOUND) {
    8737            return str;
    8738        }
    8739        return str.substring(0, pos);
    8740    }
    8741
    8742    /**
    8743     * Gets the String that is nested in between two instances of the
    8744     * same String.
    8745     *
    8746     * <p>A {@code null} input String returns {@code null}.
    8747     * A {@code null} tag returns {@code null}.</p>
    8748     *
    8749     * <pre>
    8750     * StringUtils.substringBetween(null, *)            = null
    8751     * StringUtils.substringBetween("", "")             = ""
    8752     * StringUtils.substringBetween("", "tag")          = null
    8753     * StringUtils.substringBetween("tagabctag", null)  = null
    8754     * StringUtils.substringBetween("tagabctag", "")    = ""
    8755     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    8756     * </pre>
    8757     *
    8758     * @param str  the String containing the substring, may be null
    8759     * @param tag  the String before and after the substring, may be null
    8760     * @return the substring, {@code null} if no match
    8761     * @since 2.0
    8762     */
    8763    public static String substringBetween(final String str, final String tag) {
    8764        return substringBetween(str, tag, tag);
    8765    }
    8766
    8767    /**
    8768     * Gets the String that is nested in between two Strings.
    8769     * Only the first match is returned.
    8770     *
    8771     * <p>A {@code null} input String returns {@code null}.
    8772     * A {@code null} open/close returns {@code null} (no match).
    8773     * An empty ("") open and close returns an empty string.</p>
    8774     *
    8775     * <pre>
    8776     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    8777     * StringUtils.substringBetween(null, *, *)          = null
    8778     * StringUtils.substringBetween(*, null, *)          = null
    8779     * StringUtils.substringBetween(*, *, null)          = null
    8780     * StringUtils.substringBetween("", "", "")          = ""
    8781     * StringUtils.substringBetween("", "", "]")         = null
    8782     * StringUtils.substringBetween("", "[", "]")        = null
    8783     * StringUtils.substringBetween("yabcz", "", "")     = ""
    8784     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    8785     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    8786     * </pre>
    8787     *
    8788     * @param str  the String containing the substring, may be null
    8789     * @param open  the String before the substring, may be null
    8790     * @param close  the String after the substring, may be null
    8791     * @return the substring, {@code null} if no match
    8792     * @since 2.0
    8793     */
    8794    public static String substringBetween(final String str, final String open, final String close) {
    8795        if (!ObjectUtils.allNotNull(str, open, close)) {
    8796            return null;
    8797        }
    8798        final int start = str.indexOf(open);
    8799        if (start != INDEX_NOT_FOUND) {
    8800            final int end = str.indexOf(close, start + open.length());
    8801            if (end != INDEX_NOT_FOUND) {
    8802                return str.substring(start + open.length(), end);
    8803            }
    8804        }
    8805        return null;
    8806    }
    8807
    8808    /**
    8809     * Searches a String for substrings delimited by a start and end tag,
    8810     * returning all matching substrings in an array.
    8811     *
    8812     * <p>A {@code null} input String returns {@code null}.
    8813     * A {@code null} open/close returns {@code null} (no match).
    8814     * An empty ("") open/close returns {@code null} (no match).</p>
    8815     *
    8816     * <pre>
    8817     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    8818     * StringUtils.substringsBetween(null, *, *)            = null
    8819     * StringUtils.substringsBetween(*, null, *)            = null
    8820     * StringUtils.substringsBetween(*, *, null)            = null
    8821     * StringUtils.substringsBetween("", "[", "]")          = []
    8822     * </pre>
    8823     *
    8824     * @param str  the String containing the substrings, null returns null, empty returns empty
    8825     * @param open  the String identifying the start of the substring, empty returns null
    8826     * @param close  the String identifying the end of the substring, empty returns null
    8827     * @return a String Array of substrings, or {@code null} if no match
    8828     * @since 2.3
    8829     */
    8830    public static String[] substringsBetween(final String str, final String open, final String close) {
    8831        if (str == null || isEmpty(open) || isEmpty(close)) {
    8832            return null;
    8833        }
    8834        final int strLen = str.length();
    8835        if (strLen == 0) {
    8836            return ArrayUtils.EMPTY_STRING_ARRAY;
    8837        }
    8838        final int closeLen = close.length();
    8839        final int openLen = open.length();
    8840        final List<String> list = new ArrayList<>();
    8841        int pos = 0;
    8842        while (pos < strLen - closeLen) {
    8843            int start = str.indexOf(open, pos);
    8844            if (start < 0) {
    8845                break;
    8846            }
    8847            start += openLen;
    8848            final int end = str.indexOf(close, start);
    8849            if (end < 0) {
    8850                break;
    8851            }
    8852            list.add(str.substring(start, end));
    8853            pos = end + closeLen;
    8854        }
    8855        if (list.isEmpty()) {
    8856            return null;
    8857        }
    8858        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    8859    }
    8860
    8861    /**
    8862     * Swaps the case of a String changing upper and title case to
    8863     * lower case, and lower case to upper case.
    8864     *
    8865     * <ul>
    8866     *  <li>Upper case character converts to Lower case</li>
    8867     *  <li>Title case character converts to Lower case</li>
    8868     *  <li>Lower case character converts to Upper case</li>
    8869     * </ul>
    8870     *
    8871     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
    8872     * A {@code null} input String returns {@code null}.</p>
    8873     *
    8874     * <pre>
    8875     * StringUtils.swapCase(null)                 = null
    8876     * StringUtils.swapCase("")                   = ""
    8877     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    8878     * </pre>
    8879     *
    8880     * <p>NOTE: This method changed in Lang version 2.0.
    8881     * It no longer performs a word based algorithm.
    8882     * If you only use ASCII, you will notice no change.
    8883     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
    8884     *
    8885     * @param str  the String to swap case, may be null
    8886     * @return the changed String, {@code null} if null String input
    8887     */
    8888    public static String swapCase(final String str) {
    8889        if (isEmpty(str)) {
    8890            return str;
    8891        }
    8892
    8893        final int strLen = str.length();
    8894        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    8895        int outOffset = 0;
    8896        for (int i = 0; i < strLen; ) {
    8897            final int oldCodepoint = str.codePointAt(i);
    8898            final int newCodePoint;
    8899            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
    8900                newCodePoint = Character.toLowerCase(oldCodepoint);
    8901            } else if (Character.isLowerCase(oldCodepoint)) {
    8902                newCodePoint = Character.toUpperCase(oldCodepoint);
    8903            } else {
    8904                newCodePoint = oldCodepoint;
    8905            }
    8906            newCodePoints[outOffset++] = newCodePoint;
    8907            i += Character.charCount(newCodePoint);
    8908         }
    8909        return new String(newCodePoints, 0, outOffset);
    8910    }
    8911
    8912    /**
    8913     * Converts a {@link CharSequence} into an array of code points.
    8914     *
    8915     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
    8916     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
    8917     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
    8918     *
    8919     * <pre>
    8920     * StringUtils.toCodePoints(null)   =  null
    8921     * StringUtils.toCodePoints("")     =  []  // empty array
    8922     * </pre>
    8923     *
    8924     * @param cs the character sequence to convert
    8925     * @return an array of code points
    8926     * @since 3.6
    8927     */
    8928    public static int[] toCodePoints(final CharSequence cs) {
    8929        if (cs == null) {
    8930            return null;
    8931        }
    8932        if (cs.length() == 0) {
    8933            return ArrayUtils.EMPTY_INT_ARRAY;
    8934        }
    8935
    8936        final String s = cs.toString();
    8937        final int[] result = new int[s.codePointCount(0, s.length())];
    8938        int index = 0;
    8939        for (int i = 0; i < result.length; i++) {
    8940            result[i] = s.codePointAt(index);
    8941            index += Character.charCount(result[i]);
    8942        }
    8943        return result;
    8944    }
    8945
    8946    /**
    8947     * Converts a {@code byte[]} to a String using the specified character encoding.
    8948     *
    8949     * @param bytes
    8950     *            the byte array to read from
    8951     * @param charset
    8952     *            the encoding to use, if null then use the platform default
    8953     * @return a new String
    8954     * @throws NullPointerException
    8955     *             if {@code bytes} is null
    8956     * @since 3.2
    8957     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
    8958     */
    8959    public static String toEncodedString(final byte[] bytes, final Charset charset) {
    8960        return new String(bytes, Charsets.toCharset(charset));
    8961    }
    8962
    8963    /**
    8964     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
    8965     *
    8966     * @param source A source String or null.
    8967     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
    8968     * @since 3.10
    8969     */
    8970    public static String toRootLowerCase(final String source) {
    8971        return source == null ? null : source.toLowerCase(Locale.ROOT);
    8972    }
    8973
    8974    /**
    8975     * Converts the given source String as a upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
    8976     *
    8977     * @param source A source String or null.
    8978     * @return the given source String as a upper-case using the {@link Locale#ROOT} locale or null.
    8979     * @since 3.10
    8980     */
    8981    public static String toRootUpperCase(final String source) {
    8982        return source == null ? null : source.toUpperCase(Locale.ROOT);
    8983    }
    8984
    8985    /**
    8986     * Converts a {@code byte[]} to a String using the specified character encoding.
    8987     *
    8988     * @param bytes
    8989     *            the byte array to read from
    8990     * @param charsetName
    8991     *            the encoding to use, if null then use the platform default
    8992     * @return a new String
    8993     * @throws UnsupportedEncodingException
    8994     *             Never thrown
    8995     * @throws NullPointerException
    8996     *             if the input is null
    8997     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
    8998     * @since 3.1
    8999     */
    9000    @Deprecated
    9001    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
    9002        return new String(bytes, Charsets.toCharset(charsetName));
    9003    }
    9004
    9005    private static String toStringOrEmpty(final Object obj) {
    9006        return Objects.toString(obj, EMPTY);
    9007    }
    9008
    9009    /**
    9010     * Removes control characters (char &lt;= 32) from both
    9011     * ends of this String, handling {@code null} by returning
    9012     * {@code null}.
    9013     *
    9014     * <p>The String is trimmed using {@link String#trim()}.
    9015     * Trim removes start and end characters &lt;= 32.
    9016     * To strip whitespace use {@link #strip(String)}.</p>
    9017     *
    9018     * <p>To trim your choice of characters, use the
    9019     * {@link #strip(String, String)} methods.</p>
    9020     *
    9021     * <pre>
    9022     * StringUtils.trim(null)          = null
    9023     * StringUtils.trim("")            = ""
    9024     * StringUtils.trim("     ")       = ""
    9025     * StringUtils.trim("abc")         = "abc"
    9026     * StringUtils.trim("    abc    ") = "abc"
    9027     * </pre>
    9028     *
    9029     * @param str  the String to be trimmed, may be null
    9030     * @return the trimmed string, {@code null} if null String input
    9031     */
    9032    public static String trim(final String str) {
    9033        return str == null ? null : str.trim();
    9034    }
    9035
    9036    /**
    9037     * Removes control characters (char &lt;= 32) from both
    9038     * ends of this String returning an empty String ("") if the String
    9039     * is empty ("") after the trim or if it is {@code null}.
    9040     *
    9041     * <p>The String is trimmed using {@link String#trim()}.
    9042     * Trim removes start and end characters &lt;= 32.
    9043     * To strip whitespace use {@link #stripToEmpty(String)}.
    9044     *
    9045     * <pre>
    9046     * StringUtils.trimToEmpty(null)          = ""
    9047     * StringUtils.trimToEmpty("")            = ""
    9048     * StringUtils.trimToEmpty("     ")       = ""
    9049     * StringUtils.trimToEmpty("abc")         = "abc"
    9050     * StringUtils.trimToEmpty("    abc    ") = "abc"
    9051     * </pre>
    9052     *
    9053     * @param str  the String to be trimmed, may be null
    9054     * @return the trimmed String, or an empty String if {@code null} input
    9055     * @since 2.0
    9056     */
    9057    public static String trimToEmpty(final String str) {
    9058        return str == null ? EMPTY : str.trim();
    9059    }
    9060
    9061    /**
    9062     * Removes control characters (char &lt;= 32) from both
    9063     * ends of this String returning {@code null} if the String is
    9064     * empty ("") after the trim or if it is {@code null}.
    9065     *
    9066     * <p>The String is trimmed using {@link String#trim()}.
    9067     * Trim removes start and end characters &lt;= 32.
    9068     * To strip whitespace use {@link #stripToNull(String)}.
    9069     *
    9070     * <pre>
    9071     * StringUtils.trimToNull(null)          = null
    9072     * StringUtils.trimToNull("")            = null
    9073     * StringUtils.trimToNull("     ")       = null
    9074     * StringUtils.trimToNull("abc")         = "abc"
    9075     * StringUtils.trimToNull("    abc    ") = "abc"
    9076     * </pre>
    9077     *
    9078     * @param str  the String to be trimmed, may be null
    9079     * @return the trimmed String,
    9080     *  {@code null} if only chars &lt;= 32, empty or null String input
    9081     * @since 2.0
    9082     */
    9083    public static String trimToNull(final String str) {
    9084        final String ts = trim(str);
    9085        return isEmpty(ts) ? null : ts;
    9086    }
    9087
    9088    /**
    9089     * Truncates a String. This will turn
    9090     * "Now is the time for all good men" into "Now is the time for".
    9091     *
    9092     * <p>Specifically:</p>
    9093     * <ul>
    9094     *   <li>If {@code str} is less than {@code maxWidth} characters
    9095     *       long, return it.</li>
    9096     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
    9097     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    9098     *       {@link IllegalArgumentException}.</li>
    9099     *   <li>In no case will it return a String of length greater than
    9100     *       {@code maxWidth}.</li>
    9101     * </ul>
    9102     *
    9103     * <pre>
    9104     * StringUtils.truncate(null, 0)       = null
    9105     * StringUtils.truncate(null, 2)       = null
    9106     * StringUtils.truncate("", 4)         = ""
    9107     * StringUtils.truncate("abcdefg", 4)  = "abcd"
    9108     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
    9109     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
    9110     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
    9111     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
    9112     * </pre>
    9113     *
    9114     * @param str  the String to truncate, may be null
    9115     * @param maxWidth  maximum length of result String, must be positive
    9116     * @return truncated String, {@code null} if null String input
    9117     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
    9118     * @since 3.5
    9119     */
    9120    public static String truncate(final String str, final int maxWidth) {
    9121        return truncate(str, 0, maxWidth);
    9122    }
    9123
    9124    /**
    9125     * Truncates a String. This will turn
    9126     * "Now is the time for all good men" into "is the time for all".
    9127     *
    9128     * <p>Works like {@code truncate(String, int)}, but allows you to specify
    9129     * a "left edge" offset.
    9130     *
    9131     * <p>Specifically:</p>
    9132     * <ul>
    9133     *   <li>If {@code str} is less than {@code maxWidth} characters
    9134     *       long, return it.</li>
    9135     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
    9136     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    9137     *       {@link IllegalArgumentException}.</li>
    9138     *   <li>If {@code offset} is less than {@code 0}, throw an
    9139     *       {@link IllegalArgumentException}.</li>
    9140     *   <li>In no case will it return a String of length greater than
    9141     *       {@code maxWidth}.</li>
    9142     * </ul>
    9143     *
    9144     * <pre>
    9145     * StringUtils.truncate(null, 0, 0) = null
    9146     * StringUtils.truncate(null, 2, 4) = null
    9147     * StringUtils.truncate("", 0, 10) = ""
    9148     * StringUtils.truncate("", 2, 10) = ""
    9149     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
    9150     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
    9151     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
    9152     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
    9153     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
    9154     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
    9155     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
    9156     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
    9157     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
    9158     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
    9159     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
    9160     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
    9161     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
    9162     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
    9163     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
    9164     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
    9165     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
    9166     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
    9167     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
    9168     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
    9169     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
    9170     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
    9171     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
    9172     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
    9173     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
    9174     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
    9175     * </pre>
    9176     *
    9177     * @param str  the String to truncate, may be null
    9178     * @param offset  left edge of source String
    9179     * @param maxWidth  maximum length of result String, must be positive
    9180     * @return truncated String, {@code null} if null String input
    9181     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
    9182     * @since 3.5
    9183     */
    9184    public static String truncate(final String str, final int offset, final int maxWidth) {
    9185        if (offset < 0) {
    9186            throw new IllegalArgumentException("offset cannot be negative");
    9187        }
    9188        if (maxWidth < 0) {
    9189            throw new IllegalArgumentException("maxWith cannot be negative");
    9190        }
    9191        if (str == null) {
    9192            return null;
    9193        }
    9194        if (offset > str.length()) {
    9195            return EMPTY;
    9196        }
    9197        if (str.length() > maxWidth) {
    9198            final int ix = Math.min(offset + maxWidth, str.length());
    9199            return str.substring(offset, ix);
    9200        }
    9201        return str.substring(offset);
    9202    }
    9203
    9204    /**
    9205     * Uncapitalizes a String, changing the first character to lower case as
    9206     * per {@link Character#toLowerCase(int)}. No other characters are changed.
    9207     *
    9208     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
    9209     * A {@code null} input String returns {@code null}.</p>
    9210     *
    9211     * <pre>
    9212     * StringUtils.uncapitalize(null)  = null
    9213     * StringUtils.uncapitalize("")    = ""
    9214     * StringUtils.uncapitalize("cat") = "cat"
    9215     * StringUtils.uncapitalize("Cat") = "cat"
    9216     * StringUtils.uncapitalize("CAT") = "cAT"
    9217     * </pre>
    9218     *
    9219     * @param str the String to uncapitalize, may be null
    9220     * @return the uncapitalized String, {@code null} if null String input
    9221     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
    9222     * @see #capitalize(String)
    9223     * @since 2.0
    9224     */
    9225    public static String uncapitalize(final String str) {
    9226        final int strLen = length(str);
    9227        if (strLen == 0) {
    9228            return str;
    9229        }
    9230
    9231        final int firstCodePoint = str.codePointAt(0);
    9232        final int newCodePoint = Character.toLowerCase(firstCodePoint);
    9233        if (firstCodePoint == newCodePoint) {
    9234            // already capitalized
    9235            return str;
    9236        }
    9237
    9238        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    9239        int outOffset = 0;
    9240        newCodePoints[outOffset++] = newCodePoint; // copy the first code point
    9241        for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) {
    9242            final int codePoint = str.codePointAt(inOffset);
    9243            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
    9244            inOffset += Character.charCount(codePoint);
    9245         }
    9246        return new String(newCodePoints, 0, outOffset);
    9247    }
    9248
    9249    /**
    9250     * Unwraps a given string from a character.
    9251     *
    9252     * <pre>
    9253     * StringUtils.unwrap(null, null)         = null
    9254     * StringUtils.unwrap(null, '\0')         = null
    9255     * StringUtils.unwrap(null, '1')          = null
    9256     * StringUtils.unwrap("a", 'a')           = "a"
    9257     * StringUtils.unwrap("aa", 'a')           = ""
    9258     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
    9259     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
    9260     * StringUtils.unwrap("A", '#')           = "A"
    9261     * StringUtils.unwrap("#A", '#')          = "#A"
    9262     * StringUtils.unwrap("A#", '#')          = "A#"
    9263     * </pre>
    9264     *
    9265     * @param str
    9266     *          the String to be unwrapped, can be null
    9267     * @param wrapChar
    9268     *          the character used to unwrap
    9269     * @return unwrapped String or the original string
    9270     *          if it is not quoted properly with the wrapChar
    9271     * @since 3.6
    9272     */
    9273    public static String unwrap(final String str, final char wrapChar) {
    9274        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
    9275            return str;
    9276        }
    9277
    9278        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
    9279            final int startIndex = 0;
    9280            final int endIndex = str.length() - 1;
    9281
    9282            return str.substring(startIndex + 1, endIndex);
    9283        }
    9284
    9285        return str;
    9286    }
    9287
    9288    /**
    9289     * Unwraps a given string from another string.
    9290     *
    9291     * <pre>
    9292     * StringUtils.unwrap(null, null)         = null
    9293     * StringUtils.unwrap(null, "")           = null
    9294     * StringUtils.unwrap(null, "1")          = null
    9295     * StringUtils.unwrap("a", "a")           = "a"
    9296     * StringUtils.unwrap("aa", "a")          = ""
    9297     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
    9298     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
    9299     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
    9300     * StringUtils.unwrap("A", "#")           = "A"
    9301     * StringUtils.unwrap("#A", "#")          = "#A"
    9302     * StringUtils.unwrap("A#", "#")          = "A#"
    9303     * </pre>
    9304     *
    9305     * @param str
    9306     *          the String to be unwrapped, can be null
    9307     * @param wrapToken
    9308     *          the String used to unwrap
    9309     * @return unwrapped String or the original string
    9310     *          if it is not quoted properly with the wrapToken
    9311     * @since 3.6
    9312     */
    9313    public static String unwrap(final String str, final String wrapToken) {
    9314        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
    9315            return str;
    9316        }
    9317
    9318        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
    9319            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
    9320        }
    9321
    9322        return str;
    9323    }
    9324
    9325    /**
    9326     * Converts a String to upper case as per {@link String#toUpperCase()}.
    9327     *
    9328     * <p>A {@code null} input String returns {@code null}.</p>
    9329     *
    9330     * <pre>
    9331     * StringUtils.upperCase(null)  = null
    9332     * StringUtils.upperCase("")    = ""
    9333     * StringUtils.upperCase("aBc") = "ABC"
    9334     * </pre>
    9335     *
    9336     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
    9337     * the result of this method is affected by the current locale.
    9338     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
    9339     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    9340     *
    9341     * @param str  the String to upper case, may be null
    9342     * @return the upper-cased String, {@code null} if null String input
    9343     */
    9344    public static String upperCase(final String str) {
    9345        if (str == null) {
    9346            return null;
    9347        }
    9348        return str.toUpperCase();
    9349    }
    9350
    9351    /**
    9352     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
    9353     *
    9354     * <p>A {@code null} input String returns {@code null}.</p>
    9355     *
    9356     * <pre>
    9357     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    9358     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    9359     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    9360     * </pre>
    9361     *
    9362     * @param str  the String to upper case, may be null
    9363     * @param locale  the locale that defines the case transformation rules, must not be null
    9364     * @return the upper-cased String, {@code null} if null String input
    9365     * @since 2.5
    9366     */
    9367    public static String upperCase(final String str, final Locale locale) {
    9368        if (str == null) {
    9369            return null;
    9370        }
    9371        return str.toUpperCase(LocaleUtils.toLocale(locale));
    9372    }
    9373
    9374    /**
    9375     * Returns the string representation of the {@code char} array or null.
    9376     *
    9377     * @param value the character array.
    9378     * @return a String or null
    9379     * @see String#valueOf(char[])
    9380     * @since 3.9
    9381     */
    9382    public static String valueOf(final char[] value) {
    9383        return value == null ? null : String.valueOf(value);
    9384    }
    9385
    9386    /**
    9387     * Wraps a string with a char.
    9388     *
    9389     * <pre>
    9390     * StringUtils.wrap(null, *)        = null
    9391     * StringUtils.wrap("", *)          = ""
    9392     * StringUtils.wrap("ab", '\0')     = "ab"
    9393     * StringUtils.wrap("ab", 'x')      = "xabx"
    9394     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9395     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
    9396     * </pre>
    9397     *
    9398     * @param str
    9399     *            the string to be wrapped, may be {@code null}
    9400     * @param wrapWith
    9401     *            the char that will wrap {@code str}
    9402     * @return the wrapped string, or {@code null} if {@code str==null}
    9403     * @since 3.4
    9404     */
    9405    public static String wrap(final String str, final char wrapWith) {
    9406
    9407        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9408            return str;
    9409        }
    9410
    9411        return wrapWith + str + wrapWith;
    9412    }
    9413
    9414    /**
    9415     * Wraps a String with another String.
    9416     *
    9417     * <p>
    9418     * A {@code null} input String returns {@code null}.
    9419     * </p>
    9420     *
    9421     * <pre>
    9422     * StringUtils.wrap(null, *)         = null
    9423     * StringUtils.wrap("", *)           = ""
    9424     * StringUtils.wrap("ab", null)      = "ab"
    9425     * StringUtils.wrap("ab", "x")       = "xabx"
    9426     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9427     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
    9428     * StringUtils.wrap("ab", "'")       = "'ab'"
    9429     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
    9430     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9431     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9432     * </pre>
    9433     *
    9434     * @param str
    9435     *            the String to be wrapper, may be null
    9436     * @param wrapWith
    9437     *            the String that will wrap str
    9438     * @return wrapped String, {@code null} if null String input
    9439     * @since 3.4
    9440     */
    9441    public static String wrap(final String str, final String wrapWith) {
    9442
    9443        if (isEmpty(str) || isEmpty(wrapWith)) {
    9444            return str;
    9445        }
    9446
    9447        return wrapWith.concat(str).concat(wrapWith);
    9448    }
    9449
    9450    /**
    9451     * Wraps a string with a char if that char is missing from the start or end of the given string.
    9452     *
    9453     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
    9454     *
    9455     * <pre>
    9456     * StringUtils.wrapIfMissing(null, *)        = null
    9457     * StringUtils.wrapIfMissing("", *)          = ""
    9458     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
    9459     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
    9460     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
    9461     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
    9462     * StringUtils.wrapIfMissing("/", '/')  = "/"
    9463     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
    9464     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
    9465     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
    9466     * </pre>
    9467     *
    9468     * @param str
    9469     *            the string to be wrapped, may be {@code null}
    9470     * @param wrapWith
    9471     *            the char that will wrap {@code str}
    9472     * @return the wrapped string, or {@code null} if {@code str==null}
    9473     * @since 3.5
    9474     */
    9475    public static String wrapIfMissing(final String str, final char wrapWith) {
    9476        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9477            return str;
    9478        }
    9479        final boolean wrapStart = str.charAt(0) != wrapWith;
    9480        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
    9481        if (!wrapStart && !wrapEnd) {
    9482            return str;
    9483        }
    9484
    9485        final StringBuilder builder = new StringBuilder(str.length() + 2);
    9486        if (wrapStart) {
    9487            builder.append(wrapWith);
    9488        }
    9489        builder.append(str);
    9490        if (wrapEnd) {
    9491            builder.append(wrapWith);
    9492        }
    9493        return builder.toString();
    9494    }
    9495
    9496    /**
    9497     * Wraps a string with a string if that string is missing from the start or end of the given string.
    9498     *
    9499     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
    9500     *
    9501     * <pre>
    9502     * StringUtils.wrapIfMissing(null, *)         = null
    9503     * StringUtils.wrapIfMissing("", *)           = ""
    9504     * StringUtils.wrapIfMissing("ab", null)      = "ab"
    9505     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
    9506     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
    9507     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
    9508     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
    9509     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
    9510     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
    9511     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
    9512     * StringUtils.wrapIfMissing("/", "/")  = "/"
    9513     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
    9514     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
    9515     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
    9516     * </pre>
    9517     *
    9518     * @param str
    9519     *            the string to be wrapped, may be {@code null}
    9520     * @param wrapWith
    9521     *            the string that will wrap {@code str}
    9522     * @return the wrapped string, or {@code null} if {@code str==null}
    9523     * @since 3.5
    9524     */
    9525    public static String wrapIfMissing(final String str, final String wrapWith) {
    9526        if (isEmpty(str) || isEmpty(wrapWith)) {
    9527            return str;
    9528        }
    9529
    9530        final boolean wrapStart = !str.startsWith(wrapWith);
    9531        final boolean wrapEnd = !str.endsWith(wrapWith);
    9532        if (!wrapStart && !wrapEnd) {
    9533            return str;
    9534        }
    9535
    9536        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
    9537        if (wrapStart) {
    9538            builder.append(wrapWith);
    9539        }
    9540        builder.append(str);
    9541        if (wrapEnd) {
    9542            builder.append(wrapWith);
    9543        }
    9544        return builder.toString();
    9545    }
    9546
    9547    /**
    9548     * {@link StringUtils} instances should NOT be constructed in
    9549     * standard programming. Instead, the class should be used as
    9550     * {@code StringUtils.trim(" foo ");}.
    9551     *
    9552     * <p>This constructor is public to permit tools that require a JavaBean
    9553     * instance to operate.</p>
    9554     */
    9555    public StringUtils() {
    9556    }
    9557
    9558}