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