    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.StringJoiner;
    031import java.util.function.Supplier;
    032import java.util.regex.Pattern;
    033
    034import org.apache.commons.lang3.function.ToBooleanBiFunction;
    035
    036/**
    037 * <p>Operations on {@link java.lang.String} that are
    038 * {@code null} safe.</p>
    039 *
    040 * <ul>
    041 *  <li><b>IsEmpty/IsBlank</b>
    042 *      - checks if a String contains text</li>
    043 *  <li><b>Trim/Strip</b>
    044 *      - removes leading and trailing whitespace</li>
    045 *  <li><b>Equals/Compare</b>
    046 *      - compares two strings in a null-safe manner</li>
    047 *  <li><b>startsWith</b>
    048 *      - check if a String starts with a prefix in a null-safe manner</li>
    049 *  <li><b>endsWith</b>
    050 *      - check if a String ends with a suffix in a null-safe manner</li>
    051 *  <li><b>IndexOf/LastIndexOf/Contains</b>
    052 *      - null-safe index-of checks
    053 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
    054 *      - index-of any of a set of Strings</li>
    055 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
    056 *      - checks if String contains only/none/any of these characters</li>
    057 *  <li><b>Substring/Left/Right/Mid</b>
    058 *      - null-safe substring extractions</li>
    059 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
    060 *      - substring extraction relative to other strings</li>
    061 *  <li><b>Split/Join</b>
    062 *      - splits a String into an array of substrings and vice versa</li>
    063 *  <li><b>Remove/Delete</b>
    064 *      - removes part of a String</li>
    065 *  <li><b>Replace/Overlay</b>
    066 *      - Searches a String and replaces one String with another</li>
    067 *  <li><b>Chomp/Chop</b>
    068 *      - removes the last part of a String</li>
    069 *  <li><b>AppendIfMissing</b>
    070 *      - appends a suffix to the end of the String if not present</li>
    071 *  <li><b>PrependIfMissing</b>
    072 *      - prepends a prefix to the start of the String if not present</li>
    073 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
    074 *      - pads a String</li>
    075 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
    076 *      - changes the case of a String</li>
    077 *  <li><b>CountMatches</b>
    078 *      - counts the number of occurrences of one String in another</li>
    079 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
    080 *      - checks the characters in a String</li>
    081 *  <li><b>DefaultString</b>
    082 *      - protects against a null input String</li>
    083 *  <li><b>Rotate</b>
    084 *      - rotate (circular shift) a String</li>
    085 *  <li><b>Reverse/ReverseDelimited</b>
    086 *      - reverses a String</li>
    087 *  <li><b>Abbreviate</b>
    088 *      - abbreviates a string using ellipses or another given String</li>
    089 *  <li><b>Difference</b>
    090 *      - compares Strings and reports on their differences</li>
    091 *  <li><b>LevenshteinDistance</b>
    092 *      - the number of changes needed to change one String into another</li>
    093 * </ul>
    094 *
    095 * <p>The {@code StringUtils} class defines certain words related to
    096 * String handling.</p>
    097 *
    098 * <ul>
    099 *  <li>null - {@code null}</li>
    100 *  <li>empty - a zero-length string ({@code ""})</li>
    101 *  <li>space - the space character ({@code ' '}, char 32)</li>
    102 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
    103 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
    104 * </ul>
    105 *
    106 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
    107 * That is to say that a {@code null} input will return {@code null}.
    108 * Where a {@code boolean} or {@code int} is being returned
    109 * details vary by method.</p>
    110 *
    111 * <p>A side effect of the {@code null} handling is that a
    112 * {@code NullPointerException} should be considered a bug in
    113 * {@code StringUtils}.</p>
    114 *
    115 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
    116 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
    117 *
    118 * <p>#ThreadSafe#</p>
    119 * @see java.lang.String
    120 * @since 1.0
    121 */
    122//@Immutable
    123public class StringUtils {
    124
    125    private static final int STRING_BUILDER_SIZE = 256;
    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="http://docs.oracle.com/javase/specs/jls/se7/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="http://docs.oracle.com/javase/specs/jls/se7/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     * <p>The maximum size to which the padding constant(s) can expand.</p>
    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     * <p>Abbreviates a String using ellipses. This will turn
    192     * "Now is the time for all good men" into "Now is the time for..."</p>
    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     *       {@code 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     * <p>Abbreviates a String using ellipses. This will turn
    227     * "Now is the time for all good men" into "...is the time for..."</p>
    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     * <p>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.</p>
    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     *       {@code 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     * <p>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.</p>
    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        } else if (isAnyEmpty(str, abbrevMarker)) {
    344            return str;
    345        }
    346        final int abbrevMarkerLength = abbrevMarker.length();
    347        final int minAbbrevWidth = abbrevMarkerLength + 1;
    348        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
    349
    350        if (maxWidth < minAbbrevWidth) {
    351            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
    352        }
    353        final int strLen = str.length();
    354        if (strLen <= maxWidth) {
    355            return str;
    356        }
    357        if (offset > strLen) {
    358            offset = strLen;
    359        }
    360        if (strLen - offset < maxWidth - abbrevMarkerLength) {
    361            offset = strLen - (maxWidth - abbrevMarkerLength);
    362        }
    363        if (offset <= abbrevMarkerLength+1) {
    364            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
    365        }
    366        if (maxWidth < minAbbrevWidthOffset) {
    367            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
    368        }
    369        if (offset + maxWidth - abbrevMarkerLength < strLen) {
    370            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
    371        }
    372        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
    373    }
    374
    375    /**
    376     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
    377     * replacement String.</p>
    378     *
    379     * <p>This abbreviation only occurs if the following criteria is met:</p>
    380     * <ul>
    381     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
    382     * <li>The length to truncate to is less than the length of the supplied String</li>
    383     * <li>The length to truncate to is greater than 0</li>
    384     * <li>The abbreviated String will have enough room for the length supplied replacement String
    385     * and the first and last characters of the supplied String for abbreviation</li>
    386     * </ul>
    387     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
    388     * </p>
    389     *
    390     * <pre>
    391     * StringUtils.abbreviateMiddle(null, null, 0)      = null
    392     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
    393     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
    394     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
    395     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
    396     * </pre>
    397     *
    398     * @param str  the String to abbreviate, may be null
    399     * @param middle the String to replace the middle characters with, may be null
    400     * @param length the length to abbreviate {@code str} to.
    401     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
    402     * @since 2.5
    403     */
    404    public static String abbreviateMiddle(final String str, final String middle, final int length) {
    405        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length()+2) {
    406            return str;
    407        }
    408
    409        final int targetSting = length-middle.length();
    410        final int startOffset = targetSting/2+targetSting%2;
    411        final int endOffset = str.length()-targetSting/2;
    412
    413        return str.substring(0, startOffset) +
    414            middle +
    415            str.substring(endOffset);
    416    }
    417
    418    /**
    419     * Appends the suffix to the end of the string if the string does not
    420     * already end with the suffix.
    421     *
    422     * @param str The string.
    423     * @param suffix The suffix to append to the end of the string.
    424     * @param ignoreCase Indicates whether the compare should ignore case.
    425     * @param suffixes Additional suffixes that are valid terminators (optional).
    426     *
    427     * @return A new String if suffix was appended, the same string otherwise.
    428     */
    429    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
    430        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
    431            return str;
    432        }
    433        if (ArrayUtils.isNotEmpty(suffixes)) {
    434            for (final CharSequence s : suffixes) {
    435                if (endsWith(str, s, ignoreCase)) {
    436                    return str;
    437                }
    438            }
    439        }
    440        return str + suffix.toString();
    441    }
    442
    443    /**
    444     * Appends the suffix to the end of the string if the string does not
    445     * already end with any of the suffixes.
    446     *
    447     * <pre>
    448     * StringUtils.appendIfMissing(null, null) = null
    449     * StringUtils.appendIfMissing("abc", null) = "abc"
    450     * StringUtils.appendIfMissing("", "xyz") = "xyz"
    451     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
    452     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
    453     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
    454     * </pre>
    455     * <p>With additional suffixes,</p>
    456     * <pre>
    457     * StringUtils.appendIfMissing(null, null, null) = null
    458     * StringUtils.appendIfMissing("abc", null, null) = "abc"
    459     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
    460     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    461     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
    462     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
    463     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
    464     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
    465     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
    466     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
    467     * </pre>
    468     *
    469     * @param str The string.
    470     * @param suffix The suffix to append to the end of the string.
    471     * @param suffixes Additional suffixes that are valid terminators.
    472     *
    473     * @return A new String if suffix was appended, the same string otherwise.
    474     *
    475     * @since 3.2
    476     */
    477    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    478        return appendIfMissing(str, suffix, false, suffixes);
    479    }
    480
    481    /**
    482     * Appends the suffix to the end of the string if the string does not
    483     * already end, case insensitive, with any of the suffixes.
    484     *
    485     * <pre>
    486     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
    487     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
    488     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
    489     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
    490     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
    491     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
    492     * </pre>
    493     * <p>With additional suffixes,</p>
    494     * <pre>
    495     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
    496     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
    497     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
    498     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    499     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    500     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "abcxyz"
    501     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
    502     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
    503     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
    504     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
    505     * </pre>
    506     *
    507     * @param str The string.
    508     * @param suffix The suffix to append to the end of the string.
    509     * @param suffixes Additional suffixes that are valid terminators.
    510     *
    511     * @return A new String if suffix was appended, the same string otherwise.
    512     *
    513     * @since 3.2
    514     */
    515    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    516        return appendIfMissing(str, suffix, true, suffixes);
    517    }
    518
    519    /**
    520     * <p>Capitalizes a String changing the first character to title case as
    521     * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
    522     *
    523     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
    524     * A {@code null} input String returns {@code null}.</p>
    525     *
    526     * <pre>
    527     * StringUtils.capitalize(null)  = null
    528     * StringUtils.capitalize("")    = ""
    529     * StringUtils.capitalize("cat") = "Cat"
    530     * StringUtils.capitalize("cAt") = "CAt"
    531     * StringUtils.capitalize("'cat'") = "'cat'"
    532     * </pre>
    533     *
    534     * @param str the String to capitalize, may be null
    535     * @return the capitalized String, {@code null} if null String input
    536     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
    537     * @see #uncapitalize(String)
    538     * @since 2.0
    539     */
    540    public static String capitalize(final String str) {
    541        final int strLen = length(str);
    542        if (strLen == 0) {
    543            return str;
    544        }
    545
    546        final int firstCodepoint = str.codePointAt(0);
    547        final int newCodePoint = Character.toTitleCase(firstCodepoint);
    548        if (firstCodepoint == newCodePoint) {
    549            // already capitalized
    550            return str;
    551        }
    552
    553        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    554        int outOffset = 0;
    555        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
    556        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
    557            final int codepoint = str.codePointAt(inOffset);
    558            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
    559            inOffset += Character.charCount(codepoint);
    560         }
    561        return new String(newCodePoints, 0, outOffset);
    562    }
    563
    564    /**
    565     * <p>Centers a String in a larger String of size {@code size}
    566     * using the space character (' ').</p>
    567     *
    568     * <p>If the size is less than the String length, the original String is returned.
    569     * A {@code null} String returns {@code null}.
    570     * A negative size is treated as zero.</p>
    571     *
    572     * <p>Equivalent to {@code center(str, size, " ")}.</p>
    573     *
    574     * <pre>
    575     * StringUtils.center(null, *)   = null
    576     * StringUtils.center("", 4)     = "    "
    577     * StringUtils.center("ab", -1)  = "ab"
    578     * StringUtils.center("ab", 4)   = " ab "
    579     * StringUtils.center("abcd", 2) = "abcd"
    580     * StringUtils.center("a", 4)    = " a  "
    581     * </pre>
    582     *
    583     * @param str  the String to center, may be null
    584     * @param size  the int size of new String, negative treated as zero
    585     * @return centered String, {@code null} if null String input
    586     */
    587    public static String center(final String str, final int size) {
    588        return center(str, size, ' ');
    589    }
    590
    591    /**
    592     * <p>Centers a String in a larger String of size {@code size}.
    593     * Uses a supplied character as the value to pad the String with.</p>
    594     *
    595     * <p>If the size is less than the String length, the String is returned.
    596     * A {@code null} String returns {@code null}.
    597     * A negative size is treated as zero.</p>
    598     *
    599     * <pre>
    600     * StringUtils.center(null, *, *)     = null
    601     * StringUtils.center("", 4, ' ')     = "    "
    602     * StringUtils.center("ab", -1, ' ')  = "ab"
    603     * StringUtils.center("ab", 4, ' ')   = " ab "
    604     * StringUtils.center("abcd", 2, ' ') = "abcd"
    605     * StringUtils.center("a", 4, ' ')    = " a  "
    606     * StringUtils.center("a", 4, 'y')    = "yayy"
    607     * </pre>
    608     *
    609     * @param str  the String to center, may be null
    610     * @param size  the int size of new String, negative treated as zero
    611     * @param padChar  the character to pad the new String with
    612     * @return centered String, {@code null} if null String input
    613     * @since 2.0
    614     */
    615    public static String center(String str, final int size, final char padChar) {
    616        if (str == null || size <= 0) {
    617            return str;
    618        }
    619        final int strLen = str.length();
    620        final int pads = size - strLen;
    621        if (pads <= 0) {
    622            return str;
    623        }
    624        str = leftPad(str, strLen + pads / 2, padChar);
    625        str = rightPad(str, size, padChar);
    626        return str;
    627    }
    628
    629    /**
    630     * <p>Centers a String in a larger String of size {@code size}.
    631     * Uses a supplied String as the value to pad the String with.</p>
    632     *
    633     * <p>If the size is less than the String length, the String is returned.
    634     * A {@code null} String returns {@code null}.
    635     * A negative size is treated as zero.</p>
    636     *
    637     * <pre>
    638     * StringUtils.center(null, *, *)     = null
    639     * StringUtils.center("", 4, " ")     = "    "
    640     * StringUtils.center("ab", -1, " ")  = "ab"
    641     * StringUtils.center("ab", 4, " ")   = " ab "
    642     * StringUtils.center("abcd", 2, " ") = "abcd"
    643     * StringUtils.center("a", 4, " ")    = " a  "
    644     * StringUtils.center("a", 4, "yz")   = "yayz"
    645     * StringUtils.center("abc", 7, null) = "  abc  "
    646     * StringUtils.center("abc", 7, "")   = "  abc  "
    647     * </pre>
    648     *
    649     * @param str  the String to center, may be null
    650     * @param size  the int size of new String, negative treated as zero
    651     * @param padStr  the String to pad the new String with, must not be null or empty
    652     * @return centered String, {@code null} if null String input
    653     * @throws IllegalArgumentException if padStr is {@code null} or empty
    654     */
    655    public static String center(String str, final int size, String padStr) {
    656        if (str == null || size <= 0) {
    657            return str;
    658        }
    659        if (isEmpty(padStr)) {
    660            padStr = SPACE;
    661        }
    662        final int strLen = str.length();
    663        final int pads = size - strLen;
    664        if (pads <= 0) {
    665            return str;
    666        }
    667        str = leftPad(str, strLen + pads / 2, padStr);
    668        str = rightPad(str, size, padStr);
    669        return str;
    670    }
    671
    672    /**
    673     * <p>Removes one newline from end of a String if it's there,
    674     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
    675     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
    676     *
    677     * <p>NOTE: This method changed in 2.0.
    678     * It now more closely matches Perl chomp.</p>
    679     *
    680     * <pre>
    681     * StringUtils.chomp(null)          = null
    682     * StringUtils.chomp("")            = ""
    683     * StringUtils.chomp("abc \r")      = "abc "
    684     * StringUtils.chomp("abc\n")       = "abc"
    685     * StringUtils.chomp("abc\r\n")     = "abc"
    686     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
    687     * StringUtils.chomp("abc\n\r")     = "abc\n"
    688     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
    689     * StringUtils.chomp("\r")          = ""
    690     * StringUtils.chomp("\n")          = ""
    691     * StringUtils.chomp("\r\n")        = ""
    692     * </pre>
    693     *
    694     * @param str  the String to chomp a newline from, may be null
    695     * @return String without newline, {@code null} if null String input
    696     */
    697    public static String chomp(final String str) {
    698        if (isEmpty(str)) {
    699            return str;
    700        }
    701
    702        if (str.length() == 1) {
    703            final char ch = str.charAt(0);
    704            if (ch == CharUtils.CR || ch == CharUtils.LF) {
    705                return EMPTY;
    706            }
    707            return str;
    708        }
    709
    710        int lastIdx = str.length() - 1;
    711        final char last = str.charAt(lastIdx);
    712
    713        if (last == CharUtils.LF) {
    714            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    715                lastIdx--;
    716            }
    717        } else if (last != CharUtils.CR) {
    718            lastIdx++;
    719        }
    720        return str.substring(0, lastIdx);
    721    }
    722
    723    /**
    724     * <p>Removes {@code separator} from the end of
    725     * {@code str} if it's there, otherwise leave it alone.</p>
    726     *
    727     * <p>NOTE: This method changed in version 2.0.
    728     * It now more closely matches Perl chomp.
    729     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
    730     * This method uses {@link String#endsWith(String)}.</p>
    731     *
    732     * <pre>
    733     * StringUtils.chomp(null, *)         = null
    734     * StringUtils.chomp("", *)           = ""
    735     * StringUtils.chomp("foobar", "bar") = "foo"
    736     * StringUtils.chomp("foobar", "baz") = "foobar"
    737     * StringUtils.chomp("foo", "foo")    = ""
    738     * StringUtils.chomp("foo ", "foo")   = "foo "
    739     * StringUtils.chomp(" foo", "foo")   = " "
    740     * StringUtils.chomp("foo", "foooo")  = "foo"
    741     * StringUtils.chomp("foo", "")       = "foo"
    742     * StringUtils.chomp("foo", null)     = "foo"
    743     * </pre>
    744     *
    745     * @param str  the String to chomp from, may be null
    746     * @param separator  separator String, may be null
    747     * @return String without trailing separator, {@code null} if null String input
    748     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
    749     */
    750    @Deprecated
    751    public static String chomp(final String str, final String separator) {
    752        return removeEnd(str, separator);
    753    }
    754
    755    /**
    756     * <p>Remove the last character from a String.</p>
    757     *
    758     * <p>If the String ends in {@code \r\n}, then remove both
    759     * of them.</p>
    760     *
    761     * <pre>
    762     * StringUtils.chop(null)          = null
    763     * StringUtils.chop("")            = ""
    764     * StringUtils.chop("abc \r")      = "abc "
    765     * StringUtils.chop("abc\n")       = "abc"
    766     * StringUtils.chop("abc\r\n")     = "abc"
    767     * StringUtils.chop("abc")         = "ab"
    768     * StringUtils.chop("abc\nabc")    = "abc\nab"
    769     * StringUtils.chop("a")           = ""
    770     * StringUtils.chop("\r")          = ""
    771     * StringUtils.chop("\n")          = ""
    772     * StringUtils.chop("\r\n")        = ""
    773     * </pre>
    774     *
    775     * @param str  the String to chop last character from, may be null
    776     * @return String without last character, {@code null} if null String input
    777     */
    778    public static String chop(final String str) {
    779        if (str == null) {
    780            return null;
    781        }
    782        final int strLen = str.length();
    783        if (strLen < 2) {
    784            return EMPTY;
    785        }
    786        final int lastIdx = strLen - 1;
    787        final String ret = str.substring(0, lastIdx);
    788        final char last = str.charAt(lastIdx);
    789        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
    790            return ret.substring(0, lastIdx - 1);
    791        }
    792        return ret;
    793    }
    794
    795    /**
    796     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
    797     * <ul>
    798     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    799     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    800     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    801     * </ul>
    802     *
    803     * <p>This is a {@code null} safe version of :</p>
    804     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    805     *
    806     * <p>{@code null} value is considered less than non-{@code null} value.
    807     * Two {@code null} references are considered equal.</p>
    808     *
    809     * <pre>
    810     * StringUtils.compare(null, null)   = 0
    811     * StringUtils.compare(null , "a")   &lt; 0
    812     * StringUtils.compare("a", null)    &gt; 0
    813     * StringUtils.compare("abc", "abc") = 0
    814     * StringUtils.compare("a", "b")     &lt; 0
    815     * StringUtils.compare("b", "a")     &gt; 0
    816     * StringUtils.compare("a", "B")     &gt; 0
    817     * StringUtils.compare("ab", "abc")  &lt; 0
    818     * </pre>
    819     *
    820     * @see #compare(String, String, boolean)
    821     * @see String#compareTo(String)
    822     * @param str1  the String to compare from
    823     * @param str2  the String to compare to
    824     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
    825     * @since 3.5
    826     */
    827    public static int compare(final String str1, final String str2) {
    828        return compare(str1, str2, true);
    829    }
    830
    831    /**
    832     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
    833     * <ul>
    834     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    835     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    836     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    837     * </ul>
    838     *
    839     * <p>This is a {@code null} safe version of :</p>
    840     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    841     *
    842     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    843     * Two {@code null} references are considered equal.</p>
    844     *
    845     * <pre>
    846     * StringUtils.compare(null, null, *)     = 0
    847     * StringUtils.compare(null , "a", true)  &lt; 0
    848     * StringUtils.compare(null , "a", false) &gt; 0
    849     * StringUtils.compare("a", null, true)   &gt; 0
    850     * StringUtils.compare("a", null, false)  &lt; 0
    851     * StringUtils.compare("abc", "abc", *)   = 0
    852     * StringUtils.compare("a", "b", *)       &lt; 0
    853     * StringUtils.compare("b", "a", *)       &gt; 0
    854     * StringUtils.compare("a", "B", *)       &gt; 0
    855     * StringUtils.compare("ab", "abc", *)    &lt; 0
    856     * </pre>
    857     *
    858     * @see String#compareTo(String)
    859     * @param str1  the String to compare from
    860     * @param str2  the String to compare to
    861     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    862     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
    863     * @since 3.5
    864     */
    865    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
    866        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    867            return 0;
    868        }
    869        if (str1 == null) {
    870            return nullIsLess ? -1 : 1;
    871        }
    872        if (str2 == null) {
    873            return nullIsLess ? 1 : - 1;
    874        }
    875        return str1.compareTo(str2);
    876    }
    877
    878    /**
    879     * <p>Compare two Strings lexicographically, ignoring case differences,
    880     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
    881     * <ul>
    882     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    883     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    884     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    885     * </ul>
    886     *
    887     * <p>This is a {@code null} safe version of :</p>
    888     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    889     *
    890     * <p>{@code null} value is considered less than non-{@code null} value.
    891     * Two {@code null} references are considered equal.
    892     * Comparison is case insensitive.</p>
    893     *
    894     * <pre>
    895     * StringUtils.compareIgnoreCase(null, null)   = 0
    896     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
    897     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
    898     * StringUtils.compareIgnoreCase("abc", "abc") = 0
    899     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
    900     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
    901     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
    902     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
    903     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
    904     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
    905     * </pre>
    906     *
    907     * @see #compareIgnoreCase(String, String, boolean)
    908     * @see String#compareToIgnoreCase(String)
    909     * @param str1  the String to compare from
    910     * @param str2  the String to compare to
    911     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    912     *          ignoring case differences.
    913     * @since 3.5
    914     */
    915    public static int compareIgnoreCase(final String str1, final String str2) {
    916        return compareIgnoreCase(str1, str2, true);
    917    }
    918
    919    /**
    920     * <p>Compare two Strings lexicographically, ignoring case differences,
    921     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
    922     * <ul>
    923     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    924     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    925     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    926     * </ul>
    927     *
    928     * <p>This is a {@code null} safe version of :</p>
    929     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    930     *
    931     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    932     * Two {@code null} references are considered equal.
    933     * Comparison is case insensitive.</p>
    934     *
    935     * <pre>
    936     * StringUtils.compareIgnoreCase(null, null, *)     = 0
    937     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
    938     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
    939     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
    940     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
    941     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
    942     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
    943     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
    944     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
    945     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
    946     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
    947     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
    948     * </pre>
    949     *
    950     * @see String#compareToIgnoreCase(String)
    951     * @param str1  the String to compare from
    952     * @param str2  the String to compare to
    953     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    954     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    955     *          ignoring case differences.
    956     * @since 3.5
    957     */
    958    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
    959        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    960            return 0;
    961        }
    962        if (str1 == null) {
    963            return nullIsLess ? -1 : 1;
    964        }
    965        if (str2 == null) {
    966            return nullIsLess ? 1 : - 1;
    967        }
    968        return str1.compareToIgnoreCase(str2);
    969    }
    970
    971    /**
    972     * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
    973     * This method uses {@link String#indexOf(String)} if possible.</p>
    974     *
    975     * <p>A {@code null} CharSequence will return {@code false}.</p>
    976     *
    977     * <pre>
    978     * StringUtils.contains(null, *)     = false
    979     * StringUtils.contains(*, null)     = false
    980     * StringUtils.contains("", "")      = true
    981     * StringUtils.contains("abc", "")   = true
    982     * StringUtils.contains("abc", "a")  = true
    983     * StringUtils.contains("abc", "z")  = false
    984     * </pre>
    985     *
    986     * @param seq  the CharSequence to check, may be null
    987     * @param searchSeq  the CharSequence to find, may be null
    988     * @return true if the CharSequence contains the search CharSequence,
    989     *  false if not or {@code null} string input
    990     * @since 2.0
    991     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
    992     */
    993    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
    994        if (seq == null || searchSeq == null) {
    995            return false;
    996        }
    997        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
    998    }
    999
    1000    /**
    1001     * <p>Checks if CharSequence contains a search character, handling {@code null}.
    1002     * This method uses {@link String#indexOf(int)} if possible.</p>
    1003     *
    1004     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
    1005     *
    1006     * <pre>
    1007     * StringUtils.contains(null, *)    = false
    1008     * StringUtils.contains("", *)      = false
    1009     * StringUtils.contains("abc", 'a') = true
    1010     * StringUtils.contains("abc", 'z') = false
    1011     * </pre>
    1012     *
    1013     * @param seq  the CharSequence to check, may be null
    1014     * @param searchChar  the character to find
    1015     * @return true if the CharSequence contains the search character,
    1016     *  false if not or {@code null} string input
    1017     * @since 2.0
    1018     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
    1019     */
    1020    public static boolean contains(final CharSequence seq, final int searchChar) {
    1021        if (isEmpty(seq)) {
    1022            return false;
    1023        }
    1024        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
    1025    }
    1026
    1027    /**
    1028     * <p>Checks if the CharSequence contains any character in the given
    1029     * set of characters.</p>
    1030     *
    1031     * <p>A {@code null} CharSequence will return {@code false}.
    1032     * A {@code null} or zero length search array will return {@code false}.</p>
    1033     *
    1034     * <pre>
    1035     * StringUtils.containsAny(null, *)                  = false
    1036     * StringUtils.containsAny("", *)                    = false
    1037     * StringUtils.containsAny(*, null)                  = false
    1038     * StringUtils.containsAny(*, [])                    = false
    1039     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    1040     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    1041     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    1042     * StringUtils.containsAny("aba", ['z'])             = false
    1043     * </pre>
    1044     *
    1045     * @param cs  the CharSequence to check, may be null
    1046     * @param searchChars  the chars to search for, may be null
    1047     * @return the {@code true} if any of the chars are found,
    1048     * {@code false} if no match or null input
    1049     * @since 2.4
    1050     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
    1051     */
    1052    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    1053        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1054            return false;
    1055        }
    1056        final int csLength = cs.length();
    1057        final int searchLength = searchChars.length;
    1058        final int csLast = csLength - 1;
    1059        final int searchLast = searchLength - 1;
    1060        for (int i = 0; i < csLength; i++) {
    1061            final char ch = cs.charAt(i);
    1062            for (int j = 0; j < searchLength; j++) {
    1063                if (searchChars[j] == ch) {
    1064                    if (Character.isHighSurrogate(ch)) {
    1065                        if (j == searchLast) {
    1066                            // missing low surrogate, fine, like String.indexOf(String)
    1067                            return true;
    1068                        }
    1069                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1070                            return true;
    1071                        }
    1072                    } else {
    1073                        // ch is in the Basic Multilingual Plane
    1074                        return true;
    1075                    }
    1076                }
    1077            }
    1078        }
    1079        return false;
    1080    }
    1081
    1082    /**
    1083     * <p>
    1084     * Checks if the CharSequence contains any character in the given set of characters.
    1085     * </p>
    1086     *
    1087     * <p>
    1088     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
    1089     * {@code false}.
    1090     * </p>
    1091     *
    1092     * <pre>
    1093     * StringUtils.containsAny(null, *)               = false
    1094     * StringUtils.containsAny("", *)                 = false
    1095     * StringUtils.containsAny(*, null)               = false
    1096     * StringUtils.containsAny(*, "")                 = false
    1097     * StringUtils.containsAny("zzabyycdxx", "za")    = true
    1098     * StringUtils.containsAny("zzabyycdxx", "by")    = true
    1099     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
    1100     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
    1101     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
    1102     * StringUtils.containsAny("aba", "z")            = false
    1103     * </pre>
    1104     *
    1105     * @param cs
    1106     *            the CharSequence to check, may be null
    1107     * @param searchChars
    1108     *            the chars to search for, may be null
    1109     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
    1110     * @since 2.4
    1111     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
    1112     */
    1113    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
    1114        if (searchChars == null) {
    1115            return false;
    1116        }
    1117        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
    1118    }
    1119
    1120    /**
    1121     * <p>
    1122     * Checks if the CharSequence contains any of the CharSequences in the given array.
    1123     * </p>
    1124     *
    1125     * <p>
    1126     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1127     * return {@code false}.
    1128     * </p>
    1129     *
    1130     * <pre>
    1131     * StringUtils.containsAny(null, *)            = false
    1132     * StringUtils.containsAny("", *)              = false
    1133     * StringUtils.containsAny(*, null)            = false
    1134     * StringUtils.containsAny(*, [])              = false
    1135     * StringUtils.containsAny("abcd", "ab", null) = true
    1136     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1137     * StringUtils.containsAny("abc", "d", "abc")  = true
    1138     * </pre>
    1139     *
    1140     *
    1141     * @param cs The CharSequence to check, may be null
    1142     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1143     *        null as well.
    1144     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1145     * @since 3.4
    1146     */
    1147    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
    1148        return containsAny(StringUtils::contains, cs, searchCharSequences);
    1149    }
    1150
    1151    /**
    1152     * <p>
    1153     * Checks if the CharSequence contains any of the CharSequences in the given array.
    1154     * </p>
    1155     *
    1156     * <p>
    1157     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1158     * return {@code false}.
    1159     * </p>
    1160     *
    1161     * @param cs The CharSequence to check, may be null
    1162     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1163     *        null as well.
    1164     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1165     * @since 3.12.0
    1166     */
    1167    private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
    1168        final CharSequence cs, final CharSequence... searchCharSequences) {
    1169        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
    1170            return false;
    1171        }
    1172        for (final CharSequence searchCharSequence : searchCharSequences) {
    1173            if (test.applyAsBoolean(cs, searchCharSequence)) {
    1174                return true;
    1175            }
    1176        }
    1177        return false;
    1178    }
    1179
    1180    /**
    1181     * <p>
    1182     * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
    1183     * </p>
    1184     *
    1185     * <p>
    1186     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1187     * return {@code false}.
    1188     * </p>
    1189     *
    1190     * <pre>
    1191     * StringUtils.containsAny(null, *)            = false
    1192     * StringUtils.containsAny("", *)              = false
    1193     * StringUtils.containsAny(*, null)            = false
    1194     * StringUtils.containsAny(*, [])              = false
    1195     * StringUtils.containsAny("abcd", "ab", null) = true
    1196     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1197     * StringUtils.containsAny("abc", "d", "abc")  = true
    1198     * StringUtils.containsAny("abc", "D", "ABC")  = true
    1199     * StringUtils.containsAny("ABC", "d", "abc")  = true
    1200     * </pre>
    1201     *
    1202     *
    1203     * @param cs The CharSequence to check, may be null
    1204     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1205     *        null as well.
    1206     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1207     * @since 3.12.0
    1208     */
    1209    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
    1210        return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
    1211    }
    1212
    1213    /**
    1214     * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
    1215     * handling {@code null}. Case-insensitivity is defined as by
    1216     * {@link String#equalsIgnoreCase(String)}.
    1217     *
    1218     * <p>A {@code null} CharSequence will return {@code false}.</p>
    1219     *
    1220     * <pre>
    1221     * StringUtils.containsIgnoreCase(null, *) = false
    1222     * StringUtils.containsIgnoreCase(*, null) = false
    1223     * StringUtils.containsIgnoreCase("", "") = true
    1224     * StringUtils.containsIgnoreCase("abc", "") = true
    1225     * StringUtils.containsIgnoreCase("abc", "a") = true
    1226     * StringUtils.containsIgnoreCase("abc", "z") = false
    1227     * StringUtils.containsIgnoreCase("abc", "A") = true
    1228     * StringUtils.containsIgnoreCase("abc", "Z") = false
    1229     * </pre>
    1230     *
    1231     * @param str  the CharSequence to check, may be null
    1232     * @param searchStr  the CharSequence to find, may be null
    1233     * @return true if the CharSequence contains the search CharSequence irrespective of
    1234     * case or false if not or {@code null} string input
    1235     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
    1236     */
    1237    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1238        if (str == null || searchStr == null) {
    1239            return false;
    1240        }
    1241        final int len = searchStr.length();
    1242        final int max = str.length() - len;
    1243        for (int i = 0; i <= max; i++) {
    1244            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
    1245                return true;
    1246            }
    1247        }
    1248        return false;
    1249    }
    1250
    1251    /**
    1252     * <p>Checks that the CharSequence does not contain certain characters.</p>
    1253     *
    1254     * <p>A {@code null} CharSequence will return {@code true}.
    1255     * A {@code null} invalid character array will return {@code true}.
    1256     * An empty CharSequence (length()=0) always returns true.</p>
    1257     *
    1258     * <pre>
    1259     * StringUtils.containsNone(null, *)       = true
    1260     * StringUtils.containsNone(*, null)       = true
    1261     * StringUtils.containsNone("", *)         = true
    1262     * StringUtils.containsNone("ab", '')      = true
    1263     * StringUtils.containsNone("abab", 'xyz') = true
    1264     * StringUtils.containsNone("ab1", 'xyz')  = true
    1265     * StringUtils.containsNone("abz", 'xyz')  = false
    1266     * </pre>
    1267     *
    1268     * @param cs  the CharSequence to check, may be null
    1269     * @param searchChars  an array of invalid chars, may be null
    1270     * @return true if it contains none of the invalid chars, or is null
    1271     * @since 2.0
    1272     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
    1273     */
    1274    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    1275        if (cs == null || searchChars == null) {
    1276            return true;
    1277        }
    1278        final int csLen = cs.length();
    1279        final int csLast = csLen - 1;
    1280        final int searchLen = searchChars.length;
    1281        final int searchLast = searchLen - 1;
    1282        for (int i = 0; i < csLen; i++) {
    1283            final char ch = cs.charAt(i);
    1284            for (int j = 0; j < searchLen; j++) {
    1285                if (searchChars[j] == ch) {
    1286                    if (Character.isHighSurrogate(ch)) {
    1287                        if (j == searchLast) {
    1288                            // missing low surrogate, fine, like String.indexOf(String)
    1289                            return false;
    1290                        }
    1291                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1292                            return false;
    1293                        }
    1294                    } else {
    1295                        // ch is in the Basic Multilingual Plane
    1296                        return false;
    1297                    }
    1298                }
    1299            }
    1300        }
    1301        return true;
    1302    }
    1303
    1304    /**
    1305     * <p>Checks that the CharSequence does not contain certain characters.</p>
    1306     *
    1307     * <p>A {@code null} CharSequence will return {@code true}.
    1308     * A {@code null} invalid character array will return {@code true}.
    1309     * An empty String ("") always returns true.</p>
    1310     *
    1311     * <pre>
    1312     * StringUtils.containsNone(null, *)       = true
    1313     * StringUtils.containsNone(*, null)       = true
    1314     * StringUtils.containsNone("", *)         = true
    1315     * StringUtils.containsNone("ab", "")      = true
    1316     * StringUtils.containsNone("abab", "xyz") = true
    1317     * StringUtils.containsNone("ab1", "xyz")  = true
    1318     * StringUtils.containsNone("abz", "xyz")  = false
    1319     * </pre>
    1320     *
    1321     * @param cs  the CharSequence to check, may be null
    1322     * @param invalidChars  a String of invalid chars, may be null
    1323     * @return true if it contains none of the invalid chars, or is null
    1324     * @since 2.0
    1325     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    1326     */
    1327    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
    1328        if (invalidChars == null) {
    1329            return true;
    1330        }
    1331        return containsNone(cs, invalidChars.toCharArray());
    1332    }
    1333
    1334    /**
    1335     * <p>Checks if the CharSequence contains only certain characters.</p>
    1336     *
    1337     * <p>A {@code null} CharSequence will return {@code false}.
    1338     * A {@code null} valid character array will return {@code false}.
    1339     * An empty CharSequence (length()=0) always returns {@code true}.</p>
    1340     *
    1341     * <pre>
    1342     * StringUtils.containsOnly(null, *)       = false
    1343     * StringUtils.containsOnly(*, null)       = false
    1344     * StringUtils.containsOnly("", *)         = true
    1345     * StringUtils.containsOnly("ab", '')      = false
    1346     * StringUtils.containsOnly("abab", 'abc') = true
    1347     * StringUtils.containsOnly("ab1", 'abc')  = false
    1348     * StringUtils.containsOnly("abz", 'abc')  = false
    1349     * </pre>
    1350     *
    1351     * @param cs  the String to check, may be null
    1352     * @param valid  an array of valid chars, may be null
    1353     * @return true if it only contains valid chars and is non-null
    1354     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
    1355     */
    1356    public static boolean containsOnly(final CharSequence cs, final char... valid) {
    1357        // All these pre-checks are to maintain API with an older version
    1358        if (valid == null || cs == null) {
    1359            return false;
    1360        }
    1361        if (cs.length() == 0) {
    1362            return true;
    1363        }
    1364        if (valid.length == 0) {
    1365            return false;
    1366        }
    1367        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    1368    }
    1369
    1370    /**
    1371     * <p>Checks if the CharSequence contains only certain characters.</p>
    1372     *
    1373     * <p>A {@code null} CharSequence will return {@code false}.
    1374     * A {@code null} valid character String will return {@code false}.
    1375     * An empty String (length()=0) always returns {@code true}.</p>
    1376     *
    1377     * <pre>
    1378     * StringUtils.containsOnly(null, *)       = false
    1379     * StringUtils.containsOnly(*, null)       = false
    1380     * StringUtils.containsOnly("", *)         = true
    1381     * StringUtils.containsOnly("ab", "")      = false
    1382     * StringUtils.containsOnly("abab", "abc") = true
    1383     * StringUtils.containsOnly("ab1", "abc")  = false
    1384     * StringUtils.containsOnly("abz", "abc")  = false
    1385     * </pre>
    1386     *
    1387     * @param cs  the CharSequence to check, may be null
    1388     * @param validChars  a String of valid chars, may be null
    1389     * @return true if it only contains valid chars and is non-null
    1390     * @since 2.0
    1391     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    1392     */
    1393    public static boolean containsOnly(final CharSequence cs, final String validChars) {
    1394        if (cs == null || validChars == null) {
    1395            return false;
    1396        }
    1397        return containsOnly(cs, validChars.toCharArray());
    1398    }
    1399
    1400    /**
    1401     * <p>Check whether the given CharSequence contains any whitespace characters.</p>
    1402     *
    1403     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1404     *
    1405     * @param seq the CharSequence to check (may be {@code null})
    1406     * @return {@code true} if the CharSequence is not empty and
    1407     * contains at least 1 (breaking) whitespace character
    1408     * @since 3.0
    1409     */
    1410    // From org.springframework.util.StringUtils, under Apache License 2.0
    1411    public static boolean containsWhitespace(final CharSequence seq) {
    1412        if (isEmpty(seq)) {
    1413            return false;
    1414        }
    1415        final int strLen = seq.length();
    1416        for (int i = 0; i < strLen; i++) {
    1417            if (Character.isWhitespace(seq.charAt(i))) {
    1418                return true;
    1419            }
    1420        }
    1421        return false;
    1422    }
    1423
    1424    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
    1425        for (int i = 0; i < decomposed.length(); i++) {
    1426            if (decomposed.charAt(i) == '\u0141') {
    1427                decomposed.setCharAt(i, 'L');
    1428            } else if (decomposed.charAt(i) == '\u0142') {
    1429                decomposed.setCharAt(i, 'l');
    1430            }
    1431        }
    1432    }
    1433
    1434    /**
    1435     * <p>Counts how many times the char appears in the given string.</p>
    1436     *
    1437     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1438     *
    1439     * <pre>
    1440     * StringUtils.countMatches(null, *)       = 0
    1441     * StringUtils.countMatches("", *)         = 0
    1442     * StringUtils.countMatches("abba", 0)  = 0
    1443     * StringUtils.countMatches("abba", 'a')   = 2
    1444     * StringUtils.countMatches("abba", 'b')  = 2
    1445     * StringUtils.countMatches("abba", 'x') = 0
    1446     * </pre>
    1447     *
    1448     * @param str  the CharSequence to check, may be null
    1449     * @param ch  the char to count
    1450     * @return the number of occurrences, 0 if the CharSequence is {@code null}
    1451     * @since 3.4
    1452     */
    1453    public static int countMatches(final CharSequence str, final char ch) {
    1454        if (isEmpty(str)) {
    1455            return 0;
    1456        }
    1457        int count = 0;
    1458        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
    1459        for (int i = 0; i < str.length(); i++) {
    1460            if (ch == str.charAt(i)) {
    1461                count++;
    1462            }
    1463        }
    1464        return count;
    1465    }
    1466
    1467    /**
    1468     * <p>Counts how many times the substring appears in the larger string.
    1469     * Note that the code only counts non-overlapping matches.</p>
    1470     *
    1471     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1472     *
    1473     * <pre>
    1474     * StringUtils.countMatches(null, *)       = 0
    1475     * StringUtils.countMatches("", *)         = 0
    1476     * StringUtils.countMatches("abba", null)  = 0
    1477     * StringUtils.countMatches("abba", "")    = 0
    1478     * StringUtils.countMatches("abba", "a")   = 2
    1479     * StringUtils.countMatches("abba", "ab")  = 1
    1480     * StringUtils.countMatches("abba", "xxx") = 0
    1481     * StringUtils.countMatches("ababa", "aba") = 1
    1482     * </pre>
    1483     *
    1484     * @param str  the CharSequence to check, may be null
    1485     * @param sub  the substring to count, may be null
    1486     * @return the number of occurrences, 0 if either CharSequence is {@code null}
    1487     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
    1488     */
    1489    public static int countMatches(final CharSequence str, final CharSequence sub) {
    1490        if (isEmpty(str) || isEmpty(sub)) {
    1491            return 0;
    1492        }
    1493        int count = 0;
    1494        int idx = 0;
    1495        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
    1496            count++;
    1497            idx += sub.length();
    1498        }
    1499        return count;
    1500    }
    1501
    1502    /**
    1503     * <p>Returns either the passed in CharSequence, or if the CharSequence is
    1504     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
    1505     *
    1506     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1507     *
    1508     * <pre>
    1509     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
    1510     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
    1511     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
    1512     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
    1513     * StringUtils.defaultIfBlank("", null)      = null
    1514     * </pre>
    1515     * @param <T> the specific kind of CharSequence
    1516     * @param str the CharSequence to check, may be null
    1517     * @param defaultStr  the default CharSequence to return
    1518     *  if the input is whitespace, empty ("") or {@code null}, may be null
    1519     * @return the passed in CharSequence, or the default
    1520     * @see StringUtils#defaultString(String, String)
    1521     */
    1522    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
    1523        return isBlank(str) ? defaultStr : str;
    1524    }
    1525
    1526    /**
    1527     * <p>Returns either the passed in CharSequence, or if the CharSequence is
    1528     * empty or {@code null}, the value of {@code defaultStr}.</p>
    1529     *
    1530     * <pre>
    1531     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    1532     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    1533     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
    1534     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    1535     * StringUtils.defaultIfEmpty("", null)      = null
    1536     * </pre>
    1537     * @param <T> the specific kind of CharSequence
    1538     * @param str  the CharSequence to check, may be null
    1539     * @param defaultStr  the default CharSequence to return
    1540     *  if the input is empty ("") or {@code null}, may be null
    1541     * @return the passed in CharSequence, or the default
    1542     * @see StringUtils#defaultString(String, String)
    1543     */
    1544    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
    1545        return isEmpty(str) ? defaultStr : str;
    1546    }
    1547
    1548    /**
    1549     * <p>Returns either the passed in String,
    1550     * or if the String is {@code null}, an empty String ("").</p>
    1551     *
    1552     * <pre>
    1553     * StringUtils.defaultString(null)  = ""
    1554     * StringUtils.defaultString("")    = ""
    1555     * StringUtils.defaultString("bat") = "bat"
    1556     * </pre>
    1557     *
    1558     * @see ObjectUtils#toString(Object)
    1559     * @see String#valueOf(Object)
    1560     * @param str  the String to check, may be null
    1561     * @return the passed in String, or the empty String if it
    1562     *  was {@code null}
    1563     */
    1564    public static String defaultString(final String str) {
    1565        return defaultString(str, EMPTY);
    1566    }
    1567
    1568    /**
    1569     * <p>Returns either the passed in String, or if the String is
    1570     * {@code null}, the value of {@code defaultStr}.</p>
    1571     *
    1572     * <pre>
    1573     * StringUtils.defaultString(null, "NULL")  = "NULL"
    1574     * StringUtils.defaultString("", "NULL")    = ""
    1575     * StringUtils.defaultString("bat", "NULL") = "bat"
    1576     * </pre>
    1577     *
    1578     * @see ObjectUtils#toString(Object,String)
    1579     * @see String#valueOf(Object)
    1580     * @param str  the String to check, may be null
    1581     * @param defaultStr  the default String to return
    1582     *  if the input is {@code null}, may be null
    1583     * @return the passed in String, or the default if it was {@code null}
    1584     */
    1585    public static String defaultString(final String str, final String defaultStr) {
    1586        return str == null ? defaultStr : str;
    1587    }
    1588
    1589    /**
    1590     * <p>Deletes all whitespaces from a String as defined by
    1591     * {@link Character#isWhitespace(char)}.</p>
    1592     *
    1593     * <pre>
    1594     * StringUtils.deleteWhitespace(null)         = null
    1595     * StringUtils.deleteWhitespace("")           = ""
    1596     * StringUtils.deleteWhitespace("abc")        = "abc"
    1597     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    1598     * </pre>
    1599     *
    1600     * @param str  the String to delete whitespace from, may be null
    1601     * @return the String without whitespaces, {@code null} if null String input
    1602     */
    1603    public static String deleteWhitespace(final String str) {
    1604        if (isEmpty(str)) {
    1605            return str;
    1606        }
    1607        final int sz = str.length();
    1608        final char[] chs = new char[sz];
    1609        int count = 0;
    1610        for (int i = 0; i < sz; i++) {
    1611            if (!Character.isWhitespace(str.charAt(i))) {
    1612                chs[count++] = str.charAt(i);
    1613            }
    1614        }
    1615        if (count == sz) {
    1616            return str;
    1617        }
    1618        if (count == 0) {
    1619            return EMPTY;
    1620        }
    1621        return new String(chs, 0, count);
    1622    }
    1623
    1624    /**
    1625     * <p>Compares two Strings, and returns the portion where they differ.
    1626     * More precisely, return the remainder of the second String,
    1627     * starting from where it's different from the first. This means that
    1628     * the difference between "abc" and "ab" is the empty String and not "c". </p>
    1629     *
    1630     * <p>For example,
    1631     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
    1632     *
    1633     * <pre>
    1634     * StringUtils.difference(null, null) = null
    1635     * StringUtils.difference("", "") = ""
    1636     * StringUtils.difference("", "abc") = "abc"
    1637     * StringUtils.difference("abc", "") = ""
    1638     * StringUtils.difference("abc", "abc") = ""
    1639     * StringUtils.difference("abc", "ab") = ""
    1640     * StringUtils.difference("ab", "abxyz") = "xyz"
    1641     * StringUtils.difference("abcde", "abxyz") = "xyz"
    1642     * StringUtils.difference("abcde", "xyz") = "xyz"
    1643     * </pre>
    1644     *
    1645     * @param str1  the first String, may be null
    1646     * @param str2  the second String, may be null
    1647     * @return the portion of str2 where it differs from str1; returns the
    1648     * empty String if they are equal
    1649     * @see #indexOfDifference(CharSequence,CharSequence)
    1650     * @since 2.0
    1651     */
    1652    public static String difference(final String str1, final String str2) {
    1653        if (str1 == null) {
    1654            return str2;
    1655        }
    1656        if (str2 == null) {
    1657            return str1;
    1658        }
    1659        final int at = indexOfDifference(str1, str2);
    1660        if (at == INDEX_NOT_FOUND) {
    1661            return EMPTY;
    1662        }
    1663        return str2.substring(at);
    1664    }
    1665
    1666    /**
    1667     * <p>Check if a CharSequence ends with a specified suffix.</p>
    1668     *
    1669     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1670     * references are considered to be equal. The comparison is case sensitive.</p>
    1671     *
    1672     * <pre>
    1673     * StringUtils.endsWith(null, null)      = true
    1674     * StringUtils.endsWith(null, "def")     = false
    1675     * StringUtils.endsWith("abcdef", null)  = false
    1676     * StringUtils.endsWith("abcdef", "def") = true
    1677     * StringUtils.endsWith("ABCDEF", "def") = false
    1678     * StringUtils.endsWith("ABCDEF", "cde") = false
    1679     * StringUtils.endsWith("ABCDEF", "")    = true
    1680     * </pre>
    1681     *
    1682     * @see java.lang.String#endsWith(String)
    1683     * @param str  the CharSequence to check, may be null
    1684     * @param suffix the suffix to find, may be null
    1685     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
    1686     *  both {@code null}
    1687     * @since 2.4
    1688     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
    1689     */
    1690    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
    1691        return endsWith(str, suffix, false);
    1692    }
    1693
    1694    /**
    1695     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
    1696     *
    1697     * @see java.lang.String#endsWith(String)
    1698     * @param str  the CharSequence to check, may be null
    1699     * @param suffix the suffix to find, may be null
    1700     * @param ignoreCase indicates whether the compare should ignore case
    1701     *  (case insensitive) or not.
    1702     * @return {@code true} if the CharSequence starts with the prefix or
    1703     *  both {@code null}
    1704     */
    1705    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
    1706        if (str == null || suffix == null) {
    1707            return str == suffix;
    1708        }
    1709        if (suffix.length() > str.length()) {
    1710            return false;
    1711        }
    1712        final int strOffset = str.length() - suffix.length();
    1713        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
    1714    }
    1715
    1716    /**
    1717     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
    1718     *
    1719     * <pre>
    1720     * StringUtils.endsWithAny(null, null)      = false
    1721     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
    1722     * StringUtils.endsWithAny("abcxyz", null)     = false
    1723     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
    1724     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
    1725     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    1726     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
    1727     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
    1728     * </pre>
    1729     *
    1730     * @param sequence  the CharSequence to check, may be null
    1731     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
    1732     * @see StringUtils#endsWith(CharSequence, CharSequence)
    1733     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    1734     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
    1735     * @since 3.0
    1736     */
    1737    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    1738        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    1739            return false;
    1740        }
    1741        for (final CharSequence searchString : searchStrings) {
    1742            if (endsWith(sequence, searchString)) {
    1743                return true;
    1744            }
    1745        }
    1746        return false;
    1747    }
    1748
    1749    /**
    1750     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
    1751     *
    1752     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1753     * references are considered to be equal. The comparison is case insensitive.</p>
    1754     *
    1755     * <pre>
    1756     * StringUtils.endsWithIgnoreCase(null, null)      = true
    1757     * StringUtils.endsWithIgnoreCase(null, "def")     = false
    1758     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    1759     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    1760     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    1761     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    1762     * </pre>
    1763     *
    1764     * @see java.lang.String#endsWith(String)
    1765     * @param str  the CharSequence to check, may be null
    1766     * @param suffix the suffix to find, may be null
    1767     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
    1768     *  both {@code null}
    1769     * @since 2.4
    1770     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
    1771     */
    1772    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
    1773        return endsWith(str, suffix, true);
    1774    }
    1775
    1776    /**
    1777     * <p>Compares two CharSequences, returning {@code true} if they represent
    1778     * equal sequences of characters.</p>
    1779     *
    1780     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1781     * references are considered to be equal. The comparison is <strong>case sensitive</strong>.</p>
    1782     *
    1783     * <pre>
    1784     * StringUtils.equals(null, null)   = true
    1785     * StringUtils.equals(null, "abc")  = false
    1786     * StringUtils.equals("abc", null)  = false
    1787     * StringUtils.equals("abc", "abc") = true
    1788     * StringUtils.equals("abc", "ABC") = false
    1789     * </pre>
    1790     *
    1791     * @param cs1  the first CharSequence, may be {@code null}
    1792     * @param cs2  the second CharSequence, may be {@code null}
    1793     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
    1794     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    1795     * @see Object#equals(Object)
    1796     * @see #equalsIgnoreCase(CharSequence, CharSequence)
    1797     */
    1798    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
    1799        if (cs1 == cs2) {
    1800            return true;
    1801        }
    1802        if (cs1 == null || cs2 == null) {
    1803            return false;
    1804        }
    1805        if (cs1.length() != cs2.length()) {
    1806            return false;
    1807        }
    1808        if (cs1 instanceof String && cs2 instanceof String) {
    1809            return cs1.equals(cs2);
    1810        }
    1811        // Step-wise comparison
    1812        final int length = cs1.length();
    1813        for (int i = 0; i < length; i++) {
    1814            if (cs1.charAt(i) != cs2.charAt(i)) {
    1815                return false;
    1816            }
    1817        }
    1818        return true;
    1819    }
    1820
    1821    /**
    1822     * <p>Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1823     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.</p>
    1824     *
    1825     * <pre>
    1826     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
    1827     * StringUtils.equalsAny(null, null, null)    = true
    1828     * StringUtils.equalsAny(null, "abc", "def")  = false
    1829     * StringUtils.equalsAny("abc", null, "def")  = false
    1830     * StringUtils.equalsAny("abc", "abc", "def") = true
    1831     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
    1832     * </pre>
    1833     *
    1834     * @param string to compare, may be {@code null}.
    1835     * @param searchStrings a vararg of strings, may be {@code null}.
    1836     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
    1837     * {@code false} if {@code searchStrings} is null or contains no matches.
    1838     * @since 3.5
    1839     */
    1840    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
    1841        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1842            for (final CharSequence next : searchStrings) {
    1843                if (equals(string, next)) {
    1844                    return true;
    1845                }
    1846            }
    1847        }
    1848        return false;
    1849    }
    1850
    1851    /**
    1852     * <p>Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1853     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.</p>
    1854     *
    1855     * <pre>
    1856     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
    1857     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
    1858     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
    1859     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
    1860     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
    1861     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
    1862     * </pre>
    1863     *
    1864     * @param string to compare, may be {@code null}.
    1865     * @param searchStrings a vararg of strings, may be {@code null}.
    1866     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
    1867     * {@code false} if {@code searchStrings} is null or contains no matches.
    1868     * @since 3.5
    1869     */
    1870    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
    1871        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1872            for (final CharSequence next : searchStrings) {
    1873                if (equalsIgnoreCase(string, next)) {
    1874                    return true;
    1875                }
    1876            }
    1877        }
    1878        return false;
    1879    }
    1880
    1881    /**
    1882     * <p>Compares two CharSequences, returning {@code true} if they represent
    1883     * equal sequences of characters, ignoring case.</p>
    1884     *
    1885     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1886     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
    1887     *
    1888     * <pre>
    1889     * StringUtils.equalsIgnoreCase(null, null)   = true
    1890     * StringUtils.equalsIgnoreCase(null, "abc")  = false
    1891     * StringUtils.equalsIgnoreCase("abc", null)  = false
    1892     * StringUtils.equalsIgnoreCase("abc", "abc") = true
    1893     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    1894     * </pre>
    1895     *
    1896     * @param cs1  the first CharSequence, may be {@code null}
    1897     * @param cs2  the second CharSequence, may be {@code null}
    1898     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
    1899     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
    1900     * @see #equals(CharSequence, CharSequence)
    1901     */
    1902    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
    1903        if (cs1 == cs2) {
    1904            return true;
    1905        }
    1906        if (cs1 == null || cs2 == null) {
    1907            return false;
    1908        }
    1909        if (cs1.length() != cs2.length()) {
    1910            return false;
    1911        }
    1912        return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
    1913    }
    1914
    1915    /**
    1916     * <p>Returns the first value in the array which is not empty (""),
    1917     * {@code null} or whitespace only.</p>
    1918     *
    1919     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1920     *
    1921     * <p>If all values are blank or the array is {@code null}
    1922     * or empty then {@code null} is returned.</p>
    1923     *
    1924     * <pre>
    1925     * StringUtils.firstNonBlank(null, null, null)     = null
    1926     * StringUtils.firstNonBlank(null, "", " ")        = null
    1927     * StringUtils.firstNonBlank("abc")                = "abc"
    1928     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
    1929     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
    1930     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
    1931     * StringUtils.firstNonBlank()                     = null
    1932     * </pre>
    1933     *
    1934     * @param <T> the specific kind of CharSequence
    1935     * @param values  the values to test, may be {@code null} or empty
    1936     * @return the first value from {@code values} which is not blank,
    1937     *  or {@code null} if there are no non-blank values
    1938     * @since 3.8
    1939     */
    1940    @SafeVarargs
    1941    public static <T extends CharSequence> T firstNonBlank(final T... values) {
    1942        if (values != null) {
    1943            for (final T val : values) {
    1944                if (isNotBlank(val)) {
    1945                    return val;
    1946                }
    1947            }
    1948        }
    1949        return null;
    1950    }
    1951
    1952    /**
    1953     * <p>Returns the first value in the array which is not empty.</p>
    1954     *
    1955     * <p>If all values are empty or the array is {@code null}
    1956     * or empty then {@code null} is returned.</p>
    1957     *
    1958     * <pre>
    1959     * StringUtils.firstNonEmpty(null, null, null)   = null
    1960     * StringUtils.firstNonEmpty(null, null, "")     = null
    1961     * StringUtils.firstNonEmpty(null, "", " ")      = " "
    1962     * StringUtils.firstNonEmpty("abc")              = "abc"
    1963     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
    1964     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
    1965     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
    1966     * StringUtils.firstNonEmpty()                   = null
    1967     * </pre>
    1968     *
    1969     * @param <T> the specific kind of CharSequence
    1970     * @param values  the values to test, may be {@code null} or empty
    1971     * @return the first value from {@code values} which is not empty,
    1972     *  or {@code null} if there are no non-empty values
    1973     * @since 3.8
    1974     */
    1975    @SafeVarargs
    1976    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
    1977        if (values != null) {
    1978            for (final T val : values) {
    1979                if (isNotEmpty(val)) {
    1980                    return val;
    1981                }
    1982            }
    1983        }
    1984        return null;
    1985    }
    1986
    1987    /**
    1988     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
    1989     *
    1990     * @param string input string
    1991     * @param charset The {@link Charset} to encode the {@code String}. If null, then use the default Charset.
    1992     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
    1993     * @see String#getBytes(Charset)
    1994     * @since 3.10
    1995     */
    1996    public static byte[] getBytes(final String string, final Charset charset) {
    1997        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
    1998    }
    1999
    2000    /**
    2001     * Calls {@link String#getBytes(String)} in a null-safe manner.
    2002     *
    2003     * @param string input string
    2004     * @param charset The {@link Charset} name to encode the {@code String}. If null, then use the default Charset.
    2005     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
    2006     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
    2007     * @see String#getBytes(String)
    2008     * @since 3.10
    2009     */
    2010    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
    2011        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
    2012    }
    2013
    2014    /**
    2015     * <p>Compares all Strings in an array and returns the initial sequence of
    2016     * characters that is common to all of them.</p>
    2017     *
    2018     * <p>For example,
    2019     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
    2020     *
    2021     * <pre>
    2022     * StringUtils.getCommonPrefix(null) = ""
    2023     * StringUtils.getCommonPrefix(new String[] {}) = ""
    2024     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
    2025     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
    2026     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
    2027     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
    2028     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    2029     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    2030     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
    2031     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
    2032     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
    2033     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
    2034     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
    2035     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
    2036     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
    2037     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
    2038     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    2039     * </pre>
    2040     *
    2041     * @param strs  array of String objects, entries may be null
    2042     * @return the initial sequence of characters that are common to all Strings
    2043     * in the array; empty String if the array is null, the elements are all null
    2044     * or if there is no common prefix.
    2045     * @since 2.4
    2046     */
    2047    public static String getCommonPrefix(final String... strs) {
    2048        if (ArrayUtils.isEmpty(strs)) {
    2049            return EMPTY;
    2050        }
    2051        final int smallestIndexOfDiff = indexOfDifference(strs);
    2052        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    2053            // all strings were identical
    2054            if (strs[0] == null) {
    2055                return EMPTY;
    2056            }
    2057            return strs[0];
    2058        } else if (smallestIndexOfDiff == 0) {
    2059            // there were no common initial characters
    2060            return EMPTY;
    2061        } else {
    2062            // we found a common initial character sequence
    2063            return strs[0].substring(0, smallestIndexOfDiff);
    2064        }
    2065    }
    2066
    2067    /**
    2068     * <p>Checks if a String {@code str} contains Unicode digits,
    2069     * if yes then concatenate all the digits in {@code str} and return it as a String.</p>
    2070     *
    2071     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
    2072     *
    2073     * <pre>
    2074     * StringUtils.getDigits(null)  = null
    2075     * StringUtils.getDigits("")    = ""
    2076     * StringUtils.getDigits("abc") = ""
    2077     * StringUtils.getDigits("1000$") = "1000"
    2078     * StringUtils.getDigits("1123~45") = "112345"
    2079     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
    2080     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
    2081     * </pre>
    2082     *
    2083     * @param str the String to extract digits from, may be null
    2084     * @return String with only digits,
    2085     *           or an empty ("") String if no digits found,
    2086     *           or {@code null} String if {@code str} is null
    2087     * @since 3.6
    2088     */
    2089    public static String getDigits(final String str) {
    2090        if (isEmpty(str)) {
    2091            return str;
    2092        }
    2093        final int sz = str.length();
    2094        final StringBuilder strDigits = new StringBuilder(sz);
    2095        for (int i = 0; i < sz; i++) {
    2096            final char tempChar = str.charAt(i);
    2097            if (Character.isDigit(tempChar)) {
    2098                strDigits.append(tempChar);
    2099            }
    2100        }
    2101        return strDigits.toString();
    2102    }
    2103
    2104    /**
    2105     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
    2106     *
    2107     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
    2108     * TextMate, Atom and others. One point is given for every matched character. Subsequent
    2109     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
    2110     *
    2111     * <pre>
    2112     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
    2113     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
    2114     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
    2115     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
    2116     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
    2117     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
    2118     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
    2119     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
    2120     * </pre>
    2121     *
    2122     * @param term a full term that should be matched against, must not be null
    2123     * @param query the query that will be matched against a term, must not be null
    2124     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
    2125     *  both Strings to lower case.
    2126     * @return result score
    2127     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
    2128     * @since 3.4
    2129     * @deprecated as of 3.6, use commons-text
    2130     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
    2131     * FuzzyScore</a> instead
    2132     */
    2133    @Deprecated
    2134    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
    2135        if (term == null || query == null) {
    2136            throw new IllegalArgumentException("Strings must not be null");
    2137        } else if (locale == null) {
    2138            throw new IllegalArgumentException("Locale must not be null");
    2139        }
    2140
    2141        // fuzzy logic is case insensitive. We normalize the Strings to lower
    2142        // case right from the start. Turning characters to lower case
    2143        // via Character.toLowerCase(char) is unfortunately insufficient
    2144        // as it does not accept a locale.
    2145        final String termLowerCase = term.toString().toLowerCase(locale);
    2146        final String queryLowerCase = query.toString().toLowerCase(locale);
    2147
    2148        // the resulting score
    2149        int score = 0;
    2150
    2151        // the position in the term which will be scanned next for potential
    2152        // query character matches
    2153        int termIndex = 0;
    2154
    2155        // index of the previously matched character in the term
    2156        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
    2157
    2158        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
    2159            final char queryChar = queryLowerCase.charAt(queryIndex);
    2160
    2161            boolean termCharacterMatchFound = false;
    2162            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
    2163                final char termChar = termLowerCase.charAt(termIndex);
    2164
    2165                if (queryChar == termChar) {
    2166                    // simple character matches result in one point
    2167                    score++;
    2168
    2169                    // subsequent character matches further improve
    2170                    // the score.
    2171                    if (previousMatchingCharacterIndex + 1 == termIndex) {
    2172                        score += 2;
    2173                    }
    2174
    2175                    previousMatchingCharacterIndex = termIndex;
    2176
    2177                    // we can leave the nested loop. Every character in the
    2178                    // query can match at most one character in the term.
    2179                    termCharacterMatchFound = true;
    2180                }
    2181            }
    2182        }
    2183
    2184        return score;
    2185    }
    2186
    2187    /**
    2188     * <p>Returns either the passed in CharSequence, or if the CharSequence is
    2189     * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.</p>
    2190     *
    2191     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    2192     *
    2193     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2194     *
    2195     * <pre>
    2196     * {@code
    2197     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
    2198     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
    2199     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
    2200     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
    2201     * StringUtils.getIfBlank("", () -> null)       = null
    2202     * StringUtils.getIfBlank("", null)             = null
    2203     * }</pre>
    2204     * @param <T> the specific kind of CharSequence
    2205     * @param str the CharSequence to check, may be null
    2206     * @param defaultSupplier the supplier of default CharSequence to return
    2207     *  if the input is whitespace, empty ("") or {@code null}, may be null
    2208     * @return the passed in CharSequence, or the default
    2209     * @see StringUtils#defaultString(String, String)
    2210     * @since 3.10
    2211     */
    2212    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
    2213        return isBlank(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str;
    2214    }
    2215
    2216    /**
    2217     * <p>Returns either the passed in CharSequence, or if the CharSequence is
    2218     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.</p>
    2219     *
    2220     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2221     *
    2222     * <pre>
    2223     * {@code
    2224     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
    2225     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
    2226     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
    2227     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
    2228     * StringUtils.getIfEmpty("", () -> null)        = null
    2229     * StringUtils.getIfEmpty("", null)              = null
    2230     * }
    2231     * </pre>
    2232     * @param <T> the specific kind of CharSequence
    2233     * @param str  the CharSequence to check, may be null
    2234     * @param defaultSupplier  the supplier of default CharSequence to return
    2235     *  if the input is empty ("") or {@code null}, may be null
    2236     * @return the passed in CharSequence, or the default
    2237     * @see StringUtils#defaultString(String, String)
    2238     * @since 3.10
    2239     */
    2240    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
    2241        return isEmpty(str) ? defaultSupplier == null ? null : defaultSupplier.get() : str;
    2242    }
    2243
    2244    /**
    2245     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
    2246     *
    2247     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
    2248     * Winkler increased this measure for matching initial characters.</p>
    2249     *
    2250     * <p>This implementation is based on the Jaro Winkler similarity algorithm
    2251     * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
    2252     *
    2253     * <pre>
    2254     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
    2255     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
    2256     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
    2257     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
    2258     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
    2259     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
    2260     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
    2261     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
    2262     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
    2263     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
    2264     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
    2265     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
    2266     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
    2267     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
    2268     * </pre>
    2269     *
    2270     * @param first the first String, must not be null
    2271     * @param second the second String, must not be null
    2272     * @return result distance
    2273     * @throws IllegalArgumentException if either String input {@code null}
    2274     * @since 3.3
    2275     * @deprecated as of 3.6, use commons-text
    2276     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
    2277     * JaroWinklerDistance</a> instead
    2278     */
    2279    @Deprecated
    2280    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
    2281        final double DEFAULT_SCALING_FACTOR = 0.1;
    2282
    2283        if (first == null || second == null) {
    2284            throw new IllegalArgumentException("Strings must not be null");
    2285        }
    2286
    2287        final int[] mtp = matches(first, second);
    2288        final double m = mtp[0];
    2289        if (m == 0) {
    2290            return 0D;
    2291        }
    2292        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
    2293        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
    2294        return Math.round(jw * 100.0D) / 100.0D;
    2295    }
    2296
    2297    /**
    2298     * <p>Find the Levenshtein distance between two Strings.</p>
    2299     *
    2300     * <p>This is the number of changes needed to change one String into
    2301     * another, where each change is a single character modification (deletion,
    2302     * insertion or substitution).</p>
    2303     *
    2304     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
    2305     * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
    2306     * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
    2307     *
    2308     * <pre>
    2309     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    2310     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    2311     * StringUtils.getLevenshteinDistance("", "")              = 0
    2312     * StringUtils.getLevenshteinDistance("", "a")             = 1
    2313     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    2314     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    2315     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    2316     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    2317     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    2318     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    2319     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    2320     * </pre>
    2321     *
    2322     * @param s  the first String, must not be null
    2323     * @param t  the second String, must not be null
    2324     * @return result distance
    2325     * @throws IllegalArgumentException if either String input {@code null}
    2326     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
    2327     * getLevenshteinDistance(CharSequence, CharSequence)
    2328     * @deprecated as of 3.6, use commons-text
    2329     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2330     * LevenshteinDistance</a> instead
    2331     */
    2332    @Deprecated
    2333    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    2334        if (s == null || t == null) {
    2335            throw new IllegalArgumentException("Strings must not be null");
    2336        }
    2337
    2338        int n = s.length();
    2339        int m = t.length();
    2340
    2341        if (n == 0) {
    2342            return m;
    2343        } else if (m == 0) {
    2344            return n;
    2345        }
    2346
    2347        if (n > m) {
    2348            // swap the input strings to consume less memory
    2349            final CharSequence tmp = s;
    2350            s = t;
    2351            t = tmp;
    2352            n = m;
    2353            m = t.length();
    2354        }
    2355
    2356        final int[] p = new int[n + 1];
    2357        // indexes into strings s and t
    2358        int i; // iterates through s
    2359        int j; // iterates through t
    2360        int upper_left;
    2361        int upper;
    2362
    2363        char t_j; // jth character of t
    2364        int cost;
    2365
    2366        for (i = 0; i <= n; i++) {
    2367            p[i] = i;
    2368        }
    2369
    2370        for (j = 1; j <= m; j++) {
    2371            upper_left = p[0];
    2372            t_j = t.charAt(j - 1);
    2373            p[0] = j;
    2374
    2375            for (i = 1; i <= n; i++) {
    2376                upper = p[i];
    2377                cost = s.charAt(i - 1) == t_j ? 0 : 1;
    2378                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    2379                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
    2380                upper_left = upper;
    2381            }
    2382        }
    2383
    2384        return p[n];
    2385    }
    2386
    2387    /**
    2388     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
    2389     * threshold.</p>
    2390     *
    2391     * <p>This is the number of changes needed to change one String into
    2392     * another, where each change is a single character modification (deletion,
    2393     * insertion or substitution).</p>
    2394     *
    2395     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
    2396     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
    2397     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
    2398     *
    2399     * <pre>
    2400     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
    2401     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
    2402     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
    2403     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
    2404     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
    2405     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
    2406     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
    2407     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
    2408     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
    2409     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
    2410     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
    2411     * </pre>
    2412     *
    2413     * @param s  the first String, must not be null
    2414     * @param t  the second String, must not be null
    2415     * @param threshold the target threshold, must not be negative
    2416     * @return result distance, or {@code -1} if the distance would be greater than the threshold
    2417     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
    2418     * @deprecated as of 3.6, use commons-text
    2419     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2420     * LevenshteinDistance</a> instead
    2421     */
    2422    @Deprecated
    2423    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
    2424        if (s == null || t == null) {
    2425            throw new IllegalArgumentException("Strings must not be null");
    2426        }
    2427        if (threshold < 0) {
    2428            throw new IllegalArgumentException("Threshold must not be negative");
    2429        }
    2430
    2431        /*
    2432        This implementation only computes the distance if it's less than or equal to the
    2433        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    2434        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    2435        computing a diagonal stripe of width 2k + 1 of the cost table.
    2436        It is also possible to use this to compute the unbounded Levenshtein distance by starting
    2437        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    2438        d is the distance.
    2439
    2440        One subtlety comes from needing to ignore entries on the border of our stripe
    2441        eg.
    2442        p[] = |#|#|#|*
    2443        d[] =  *|#|#|#|
    2444        We must ignore the entry to the left of the leftmost member
    2445        We must ignore the entry above the rightmost member
    2446
    2447        Another subtlety comes from our stripe running off the matrix if the strings aren't
    2448        of the same size.  Since string s is always swapped to be the shorter of the two,
    2449        the stripe will always run off to the upper right instead of the lower left of the matrix.
    2450
    2451        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    2452        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
    2453
    2454           1 2 3 4 5
    2455        1 |#|#| | | |
    2456        2 |#|#|#| | |
    2457        3 | |#|#|#| |
    2458        4 | | |#|#|#|
    2459        5 | | | |#|#|
    2460        6 | | | | |#|
    2461        7 | | | | | |
    2462
    2463        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    2464        into one of length 7 in edit distance of 1.
    2465
    2466        Additionally, this implementation decreases memory usage by using two
    2467        single-dimensional arrays and swapping them back and forth instead of allocating
    2468        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    2469        when it's detected that the stripe has run off the matrix and initially filling the arrays with
    2470        large values so that entries we don't compute are ignored.
    2471
    2472        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
    2473         */
    2474
    2475        int n = s.length(); // length of s
    2476        int m = t.length(); // length of t
    2477
    2478        // if one string is empty, the edit distance is necessarily the length of the other
    2479        if (n == 0) {
    2480            return m <= threshold ? m : -1;
    2481        } else if (m == 0) {
    2482            return n <= threshold ? n : -1;
    2483        } else if (Math.abs(n - m) > threshold) {
    2484            // no need to calculate the distance if the length difference is greater than the threshold
    2485            return -1;
    2486        }
    2487
    2488        if (n > m) {
    2489            // swap the two strings to consume less memory
    2490            final CharSequence tmp = s;
    2491            s = t;
    2492            t = tmp;
    2493            n = m;
    2494            m = t.length();
    2495        }
    2496
    2497        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
    2498        int[] d = new int[n + 1]; // cost array, horizontally
    2499        int[] _d; // placeholder to assist in swapping p and d
    2500
    2501        // fill in starting table values
    2502        final int boundary = Math.min(n, threshold) + 1;
    2503        for (int i = 0; i < boundary; i++) {
    2504            p[i] = i;
    2505        }
    2506        // these fills ensure that the value above the rightmost entry of our
    2507        // stripe will be ignored in following loop iterations
    2508        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    2509        Arrays.fill(d, Integer.MAX_VALUE);
    2510
    2511        // iterates through t
    2512        for (int j = 1; j <= m; j++) {
    2513            final char t_j = t.charAt(j - 1); // jth character of t
    2514            d[0] = j;
    2515
    2516            // compute stripe indices, constrain to array size
    2517            final int min = Math.max(1, j - threshold);
    2518            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
    2519
    2520            // the stripe may lead off of the table if s and t are of different sizes
    2521            if (min > max) {
    2522                return -1;
    2523            }
    2524
    2525            // ignore entry left of leftmost
    2526            if (min > 1) {
    2527                d[min - 1] = Integer.MAX_VALUE;
    2528            }
    2529
    2530            // iterates through [min, max] in s
    2531            for (int i = min; i <= max; i++) {
    2532                if (s.charAt(i - 1) == t_j) {
    2533                    // diagonally left and up
    2534                    d[i] = p[i - 1];
    2535                } else {
    2536                    // 1 + minimum of cell to the left, to the top, diagonally left and up
    2537                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
    2538                }
    2539            }
    2540
    2541            // copy current distance counts to 'previous row' distance counts
    2542            _d = p;
    2543            p = d;
    2544            d = _d;
    2545        }
    2546
    2547        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    2548        // distance
    2549        if (p[n] <= threshold) {
    2550            return p[n];
    2551        }
    2552        return -1;
    2553    }
    2554
    2555    /**
    2556     * <p>Finds the first index within a CharSequence, handling {@code null}.
    2557     * This method uses {@link String#indexOf(String, int)} if possible.</p>
    2558     *
    2559     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    2560     *
    2561     * <pre>
    2562     * StringUtils.indexOf(null, *)          = -1
    2563     * StringUtils.indexOf(*, null)          = -1
    2564     * StringUtils.indexOf("", "")           = 0
    2565     * StringUtils.indexOf("", *)            = -1 (except when * = "")
    2566     * StringUtils.indexOf("aabaabaa", "a")  = 0
    2567     * StringUtils.indexOf("aabaabaa", "b")  = 2
    2568     * StringUtils.indexOf("aabaabaa", "ab") = 1
    2569     * StringUtils.indexOf("aabaabaa", "")   = 0
    2570     * </pre>
    2571     *
    2572     * @param seq  the CharSequence to check, may be null
    2573     * @param searchSeq  the CharSequence to find, may be null
    2574     * @return the first index of the search CharSequence,
    2575     *  -1 if no match or {@code null} string input
    2576     * @since 2.0
    2577     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
    2578     */
    2579    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
    2580        if (seq == null || searchSeq == null) {
    2581            return INDEX_NOT_FOUND;
    2582        }
    2583        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
    2584    }
    2585
    2586    /**
    2587     * <p>Finds the first index within a CharSequence, handling {@code null}.
    2588     * This method uses {@link String#indexOf(String, int)} if possible.</p>
    2589     *
    2590     * <p>A {@code null} CharSequence will return {@code -1}.
    2591     * A negative start position is treated as zero.
    2592     * An empty ("") search CharSequence always matches.
    2593     * A start position greater than the string length only matches
    2594     * an empty search CharSequence.</p>
    2595     *
    2596     * <pre>
    2597     * StringUtils.indexOf(null, *, *)          = -1
    2598     * StringUtils.indexOf(*, null, *)          = -1
    2599     * StringUtils.indexOf("", "", 0)           = 0
    2600     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    2601     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    2602     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    2603     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    2604     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    2605     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    2606     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    2607     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    2608     * StringUtils.indexOf("abc", "", 9)        = 3
    2609     * </pre>
    2610     *
    2611     * @param seq  the CharSequence to check, may be null
    2612     * @param searchSeq  the CharSequence to find, may be null
    2613     * @param startPos  the start position, negative treated as zero
    2614     * @return the first index of the search CharSequence (always &ge; startPos),
    2615     *  -1 if no match or {@code null} string input
    2616     * @since 2.0
    2617     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
    2618     */
    2619    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    2620        if (seq == null || searchSeq == null) {
    2621            return INDEX_NOT_FOUND;
    2622        }
    2623        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
    2624    }
    2625
    2626    /**
    2627     * Returns the index within {@code seq} of the first occurrence of
    2628     * the specified character. If a character with value
    2629     * {@code searchChar} occurs in the character sequence represented by
    2630     * {@code seq} {@code CharSequence} object, then the index (in Unicode
    2631     * code units) of the first such occurrence is returned. For
    2632     * values of {@code searchChar} in the range from 0 to 0xFFFF
    2633     * (inclusive), this is the smallest value <i>k</i> such that:
    2634     * <blockquote><pre>
    2635     * this.charAt(<i>k</i>) == searchChar
    2636     * </pre></blockquote>
    2637     * is true. For other values of {@code searchChar}, it is the
    2638     * smallest value <i>k</i> such that:
    2639     * <blockquote><pre>
    2640     * this.codePointAt(<i>k</i>) == searchChar
    2641     * </pre></blockquote>
    2642     * is true. In either case, if no such character occurs in {@code seq},
    2643     * then {@code INDEX_NOT_FOUND (-1)} is returned.
    2644     *
    2645     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
    2646     * return {@code INDEX_NOT_FOUND (-1)}.</p>
    2647     *
    2648     * <pre>
    2649     * StringUtils.indexOf(null, *)         = -1
    2650     * StringUtils.indexOf("", *)           = -1
    2651     * StringUtils.indexOf("aabaabaa", 'a') = 0
    2652     * StringUtils.indexOf("aabaabaa", 'b') = 2
    2653     * </pre>
    2654     *
    2655     * @param seq  the CharSequence to check, may be null
    2656     * @param searchChar  the character to find
    2657     * @return the first index of the search character,
    2658     *  -1 if no match or {@code null} string input
    2659     * @since 2.0
    2660     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
    2661     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
    2662     */
    2663    public static int indexOf(final CharSequence seq, final int searchChar) {
    2664        if (isEmpty(seq)) {
    2665            return INDEX_NOT_FOUND;
    2666        }
    2667        return CharSequenceUtils.indexOf(seq, searchChar, 0);
    2668    }
    2669
    2670    /**
    2671     *
    2672     * Returns the index within {@code seq} of the first occurrence of the
    2673     * specified character, starting the search at the specified index.
    2674     * <p>
    2675     * If a character with value {@code searchChar} occurs in the
    2676     * character sequence represented by the {@code seq} {@code CharSequence}
    2677     * object at an index no smaller than {@code startPos}, then
    2678     * the index of the first such occurrence is returned. For values
    2679     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
    2680     * this is the smallest value <i>k</i> such that:
    2681     * <blockquote><pre>
    2682     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    2683     * </pre></blockquote>
    2684     * is true. For other values of {@code searchChar}, it is the
    2685     * smallest value <i>k</i> such that:
    2686     * <blockquote><pre>
    2687     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    2688     * </pre></blockquote>
    2689     * is true. In either case, if no such character occurs in {@code seq}
    2690     * at or after position {@code startPos}, then
    2691     * {@code -1} is returned.
    2692     *
    2693     * <p>
    2694     * There is no restriction on the value of {@code startPos}. If it
    2695     * is negative, it has the same effect as if it were zero: this entire
    2696     * string may be searched. If it is greater than the length of this
    2697     * string, it has the same effect as if it were equal to the length of
    2698     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
    2699     * {@code null} or empty ("") CharSequence will
    2700     * return {@code (INDEX_NOT_FOUND) -1}.
    2701     *
    2702     * <p>All indices are specified in {@code char} values
    2703     * (Unicode code units).
    2704     *
    2705     * <pre>
    2706     * StringUtils.indexOf(null, *, *)          = -1
    2707     * StringUtils.indexOf("", *, *)            = -1
    2708     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    2709     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    2710     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    2711     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    2712     * </pre>
    2713     *
    2714     * @param seq  the CharSequence to check, may be null
    2715     * @param searchChar  the character to find
    2716     * @param startPos  the start position, negative treated as zero
    2717     * @return the first index of the search character (always &ge; startPos),
    2718     *  -1 if no match or {@code null} string input
    2719     * @since 2.0
    2720     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
    2721     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
    2722     */
    2723    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
    2724        if (isEmpty(seq)) {
    2725            return INDEX_NOT_FOUND;
    2726        }
    2727        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
    2728    }
    2729
    2730    /**
    2731     * <p>Search a CharSequence to find the first index of any
    2732     * character in the given set of characters.</p>
    2733     *
    2734     * <p>A {@code null} String will return {@code -1}.
    2735     * A {@code null} or zero length search array will return {@code -1}.</p>
    2736     *
    2737     * <pre>
    2738     * StringUtils.indexOfAny(null, *)                  = -1
    2739     * StringUtils.indexOfAny("", *)                    = -1
    2740     * StringUtils.indexOfAny(*, null)                  = -1
    2741     * StringUtils.indexOfAny(*, [])                    = -1
    2742     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
    2743     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
    2744     * StringUtils.indexOfAny("aba", ['z'])             = -1
    2745     * </pre>
    2746     *
    2747     * @param cs  the CharSequence to check, may be null
    2748     * @param searchChars  the chars to search for, may be null
    2749     * @return the index of any of the chars, -1 if no match or null input
    2750     * @since 2.0
    2751     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2752     */
    2753    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    2754        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2755            return INDEX_NOT_FOUND;
    2756        }
    2757        final int csLen = cs.length();
    2758        final int csLast = csLen - 1;
    2759        final int searchLen = searchChars.length;
    2760        final int searchLast = searchLen - 1;
    2761        for (int i = 0; i < csLen; i++) {
    2762            final char ch = cs.charAt(i);
    2763            for (int j = 0; j < searchLen; j++) {
    2764                if (searchChars[j] == ch) {
    2765                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
    2766                        // ch is a supplementary character
    2767                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2768                            return i;
    2769                        }
    2770                    } else {
    2771                        return i;
    2772                    }
    2773                }
    2774            }
    2775        }
    2776        return INDEX_NOT_FOUND;
    2777    }
    2778
    2779    /**
    2780     * <p>Find the first index of any of a set of potential substrings.</p>
    2781     *
    2782     * <p>A {@code null} CharSequence will return {@code -1}.
    2783     * A {@code null} or zero length search array will return {@code -1}.
    2784     * A {@code null} search array entry will be ignored, but a search
    2785     * array containing "" will return {@code 0} if {@code str} is not
    2786     * null. This method uses {@link String#indexOf(String)} if possible.</p>
    2787     *
    2788     * <pre>
    2789     * StringUtils.indexOfAny(null, *)                      = -1
    2790     * StringUtils.indexOfAny(*, null)                      = -1
    2791     * StringUtils.indexOfAny(*, [])                        = -1
    2792     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
    2793     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
    2794     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
    2795     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
    2796     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
    2797     * StringUtils.indexOfAny("", [""])                     = 0
    2798     * StringUtils.indexOfAny("", ["a"])                    = -1
    2799     * </pre>
    2800     *
    2801     * @param str  the CharSequence to check, may be null
    2802     * @param searchStrs  the CharSequences to search for, may be null
    2803     * @return the first index of any of the searchStrs in str, -1 if no match
    2804     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
    2805     */
    2806    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2807        if (str == null || searchStrs == null) {
    2808            return INDEX_NOT_FOUND;
    2809        }
    2810
    2811        // String's can't have a MAX_VALUEth index.
    2812        int ret = Integer.MAX_VALUE;
    2813
    2814        int tmp = 0;
    2815        for (final CharSequence search : searchStrs) {
    2816            if (search == null) {
    2817                continue;
    2818            }
    2819            tmp = CharSequenceUtils.indexOf(str, search, 0);
    2820            if (tmp == INDEX_NOT_FOUND) {
    2821                continue;
    2822            }
    2823
    2824            if (tmp < ret) {
    2825                ret = tmp;
    2826            }
    2827        }
    2828
    2829        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
    2830    }
    2831
    2832    /**
    2833     * <p>Search a CharSequence to find the first index of any
    2834     * character in the given set of characters.</p>
    2835     *
    2836     * <p>A {@code null} String will return {@code -1}.
    2837     * A {@code null} search string will return {@code -1}.</p>
    2838     *
    2839     * <pre>
    2840     * StringUtils.indexOfAny(null, *)            = -1
    2841     * StringUtils.indexOfAny("", *)              = -1
    2842     * StringUtils.indexOfAny(*, null)            = -1
    2843     * StringUtils.indexOfAny(*, "")              = -1
    2844     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    2845     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    2846     * StringUtils.indexOfAny("aba", "z")         = -1
    2847     * </pre>
    2848     *
    2849     * @param cs  the CharSequence to check, may be null
    2850     * @param searchChars  the chars to search for, may be null
    2851     * @return the index of any of the chars, -1 if no match or null input
    2852     * @since 2.0
    2853     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    2854     */
    2855    public static int indexOfAny(final CharSequence cs, final String searchChars) {
    2856        if (isEmpty(cs) || isEmpty(searchChars)) {
    2857            return INDEX_NOT_FOUND;
    2858        }
    2859        return indexOfAny(cs, searchChars.toCharArray());
    2860    }
    2861
    2862    /**
    2863     * <p>Searches a CharSequence to find the first index of any
    2864     * character not in the given set of characters.</p>
    2865     *
    2866     * <p>A {@code null} CharSequence will return {@code -1}.
    2867     * A {@code null} or zero length search array will return {@code -1}.</p>
    2868     *
    2869     * <pre>
    2870     * StringUtils.indexOfAnyBut(null, *)                              = -1
    2871     * StringUtils.indexOfAnyBut("", *)                                = -1
    2872     * StringUtils.indexOfAnyBut(*, null)                              = -1
    2873     * StringUtils.indexOfAnyBut(*, [])                                = -1
    2874     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
    2875     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
    2876     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
    2877
    2878     * </pre>
    2879     *
    2880     * @param cs  the CharSequence to check, may be null
    2881     * @param searchChars  the chars to search for, may be null
    2882     * @return the index of any of the chars, -1 if no match or null input
    2883     * @since 2.0
    2884     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
    2885     */
    2886    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    2887        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2888            return INDEX_NOT_FOUND;
    2889        }
    2890        final int csLen = cs.length();
    2891        final int csLast = csLen - 1;
    2892        final int searchLen = searchChars.length;
    2893        final int searchLast = searchLen - 1;
    2894        outer:
    2895        for (int i = 0; i < csLen; i++) {
    2896            final char ch = cs.charAt(i);
    2897            for (int j = 0; j < searchLen; j++) {
    2898                if (searchChars[j] == ch) {
    2899                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
    2900                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2901                            continue outer;
    2902                        }
    2903                    } else {
    2904                        continue outer;
    2905                    }
    2906                }
    2907            }
    2908            return i;
    2909        }
    2910        return INDEX_NOT_FOUND;
    2911    }
    2912
    2913    /**
    2914     * <p>Search a CharSequence to find the first index of any
    2915     * character not in the given set of characters.</p>
    2916     *
    2917     * <p>A {@code null} CharSequence will return {@code -1}.
    2918     * A {@code null} or empty search string will return {@code -1}.</p>
    2919     *
    2920     * <pre>
    2921     * StringUtils.indexOfAnyBut(null, *)            = -1
    2922     * StringUtils.indexOfAnyBut("", *)              = -1
    2923     * StringUtils.indexOfAnyBut(*, null)            = -1
    2924     * StringUtils.indexOfAnyBut(*, "")              = -1
    2925     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    2926     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
    2927     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
    2928     * </pre>
    2929     *
    2930     * @param seq  the CharSequence to check, may be null
    2931     * @param searchChars  the chars to search for, may be null
    2932     * @return the index of any of the chars, -1 if no match or null input
    2933     * @since 2.0
    2934     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
    2935     */
    2936    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
    2937        if (isEmpty(seq) || isEmpty(searchChars)) {
    2938            return INDEX_NOT_FOUND;
    2939        }
    2940        final int strLen = seq.length();
    2941        for (int i = 0; i < strLen; i++) {
    2942            final char ch = seq.charAt(i);
    2943            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
    2944            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
    2945                final char ch2 = seq.charAt(i + 1);
    2946                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
    2947                    return i;
    2948                }
    2949            } else if (!chFound) {
    2950                return i;
    2951            }
    2952        }
    2953        return INDEX_NOT_FOUND;
    2954    }
    2955
    2956    /**
    2957     * <p>Compares all CharSequences in an array and returns the index at which the
    2958     * CharSequences begin to differ.</p>
    2959     *
    2960     * <p>For example,
    2961     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
    2962     *
    2963     * <pre>
    2964     * StringUtils.indexOfDifference(null) = -1
    2965     * StringUtils.indexOfDifference(new String[] {}) = -1
    2966     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
    2967     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
    2968     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
    2969     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
    2970     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    2971     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    2972     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
    2973     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
    2974     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
    2975     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
    2976     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
    2977     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
    2978     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
    2979     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
    2980     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    2981     * </pre>
    2982     *
    2983     * @param css  array of CharSequences, entries may be null
    2984     * @return the index where the strings begin to differ; -1 if they are all equal
    2985     * @since 2.4
    2986     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    2987     */
    2988    public static int indexOfDifference(final CharSequence... css) {
    2989        if (ArrayUtils.getLength(css) <= 1) {
    2990            return INDEX_NOT_FOUND;
    2991        }
    2992        boolean anyStringNull = false;
    2993        boolean allStringsNull = true;
    2994        final int arrayLen = css.length;
    2995        int shortestStrLen = Integer.MAX_VALUE;
    2996        int longestStrLen = 0;
    2997
    2998        // find the min and max string lengths; this avoids checking to make
    2999        // sure we are not exceeding the length of the string each time through
    3000        // the bottom loop.
    3001        for (final CharSequence cs : css) {
    3002            if (cs == null) {
    3003                anyStringNull = true;
    3004                shortestStrLen = 0;
    3005            } else {
    3006                allStringsNull = false;
    3007                shortestStrLen = Math.min(cs.length(), shortestStrLen);
    3008                longestStrLen = Math.max(cs.length(), longestStrLen);
    3009            }
    3010        }
    3011
    3012        // handle lists containing all nulls or all empty strings
    3013        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
    3014            return INDEX_NOT_FOUND;
    3015        }
    3016
    3017        // handle lists containing some nulls or some empty strings
    3018        if (shortestStrLen == 0) {
    3019            return 0;
    3020        }
    3021
    3022        // find the position with the first difference across all strings
    3023        int firstDiff = -1;
    3024        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    3025            final char comparisonChar = css[0].charAt(stringPos);
    3026            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    3027                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    3028                    firstDiff = stringPos;
    3029                    break;
    3030                }
    3031            }
    3032            if (firstDiff != -1) {
    3033                break;
    3034            }
    3035        }
    3036
    3037        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    3038            // we compared all of the characters up to the length of the
    3039            // shortest string and didn't find a match, but the string lengths
    3040            // vary, so return the length of the shortest string.
    3041            return shortestStrLen;
    3042        }
    3043        return firstDiff;
    3044    }
    3045
    3046    /**
    3047     * <p>Compares two CharSequences, and returns the index at which the
    3048     * CharSequences begin to differ.</p>
    3049     *
    3050     * <p>For example,
    3051     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
    3052     *
    3053     * <pre>
    3054     * StringUtils.indexOfDifference(null, null) = -1
    3055     * StringUtils.indexOfDifference("", "") = -1
    3056     * StringUtils.indexOfDifference("", "abc") = 0
    3057     * StringUtils.indexOfDifference("abc", "") = 0
    3058     * StringUtils.indexOfDifference("abc", "abc") = -1
    3059     * StringUtils.indexOfDifference("ab", "abxyz") = 2
    3060     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    3061     * StringUtils.indexOfDifference("abcde", "xyz") = 0
    3062     * </pre>
    3063     *
    3064     * @param cs1  the first CharSequence, may be null
    3065     * @param cs2  the second CharSequence, may be null
    3066     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
    3067     * @since 2.0
    3068     * @since 3.0 Changed signature from indexOfDifference(String, String) to
    3069     * indexOfDifference(CharSequence, CharSequence)
    3070     */
    3071    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
    3072        if (cs1 == cs2) {
    3073            return INDEX_NOT_FOUND;
    3074        }
    3075        if (cs1 == null || cs2 == null) {
    3076            return 0;
    3077        }
    3078        int i;
    3079        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    3080            if (cs1.charAt(i) != cs2.charAt(i)) {
    3081                break;
    3082            }
    3083        }
    3084        if (i < cs2.length() || i < cs1.length()) {
    3085            return i;
    3086        }
    3087        return INDEX_NOT_FOUND;
    3088    }
    3089
    3090    /**
    3091     * <p>Case in-sensitive find of the first index within a CharSequence.</p>
    3092     *
    3093     * <p>A {@code null} CharSequence will return {@code -1}.
    3094     * A negative start position is treated as zero.
    3095     * An empty ("") search CharSequence always matches.
    3096     * A start position greater than the string length only matches
    3097     * an empty search CharSequence.</p>
    3098     *
    3099     * <pre>
    3100     * StringUtils.indexOfIgnoreCase(null, *)          = -1
    3101     * StringUtils.indexOfIgnoreCase(*, null)          = -1
    3102     * StringUtils.indexOfIgnoreCase("", "")           = 0
    3103     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    3104     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    3105     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    3106     * </pre>
    3107     *
    3108     * @param str  the CharSequence to check, may be null
    3109     * @param searchStr  the CharSequence to find, may be null
    3110     * @return the first index of the search CharSequence,
    3111     *  -1 if no match or {@code null} string input
    3112     * @since 2.5
    3113     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
    3114     */
    3115    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    3116        return indexOfIgnoreCase(str, searchStr, 0);
    3117    }
    3118
    3119    /**
    3120     * <p>Case in-sensitive find of the first index within a CharSequence
    3121     * from the specified position.</p>
    3122     *
    3123     * <p>A {@code null} CharSequence will return {@code -1}.
    3124     * A negative start position is treated as zero.
    3125     * An empty ("") search CharSequence always matches.
    3126     * A start position greater than the string length only matches
    3127     * an empty search CharSequence.</p>
    3128     *
    3129     * <pre>
    3130     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    3131     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    3132     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    3133     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    3134     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    3135     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    3136     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    3137     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    3138     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    3139     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    3140     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
    3141     * </pre>
    3142     *
    3143     * @param str  the CharSequence to check, may be null
    3144     * @param searchStr  the CharSequence to find, may be null
    3145     * @param startPos  the start position, negative treated as zero
    3146     * @return the first index of the search CharSequence (always &ge; startPos),
    3147     *  -1 if no match or {@code null} string input
    3148     * @since 2.5
    3149     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
    3150     */
    3151    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    3152        if (str == null || searchStr == null) {
    3153            return INDEX_NOT_FOUND;
    3154        }
    3155        if (startPos < 0) {
    3156            startPos = 0;
    3157        }
    3158        final int endLimit = str.length() - searchStr.length() + 1;
    3159        if (startPos > endLimit) {
    3160            return INDEX_NOT_FOUND;
    3161        }
    3162        if (searchStr.length() == 0) {
    3163            return startPos;
    3164        }
    3165        for (int i = startPos; i < endLimit; i++) {
    3166            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
    3167                return i;
    3168            }
    3169        }
    3170        return INDEX_NOT_FOUND;
    3171    }
    3172
    3173    /**
    3174     * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p>
    3175     *
    3176     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3177     *
    3178     * <pre>
    3179     * StringUtils.isAllBlank(null)             = true
    3180     * StringUtils.isAllBlank(null, "foo")      = false
    3181     * StringUtils.isAllBlank(null, null)       = true
    3182     * StringUtils.isAllBlank("", "bar")        = false
    3183     * StringUtils.isAllBlank("bob", "")        = false
    3184     * StringUtils.isAllBlank("  bob  ", null)  = false
    3185     * StringUtils.isAllBlank(" ", "bar")       = false
    3186     * StringUtils.isAllBlank("foo", "bar")     = false
    3187     * StringUtils.isAllBlank(new String[] {})  = true
    3188     * </pre>
    3189     *
    3190     * @param css  the CharSequences to check, may be null or empty
    3191     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
    3192     * @since 3.6
    3193     */
    3194    public static boolean isAllBlank(final CharSequence... css) {
    3195        if (ArrayUtils.isEmpty(css)) {
    3196            return true;
    3197        }
    3198        for (final CharSequence cs : css) {
    3199            if (isNotBlank(cs)) {
    3200               return false;
    3201            }
    3202        }
    3203        return true;
    3204    }
    3205
    3206    /**
    3207     * <p>Checks if all of the CharSequences are empty ("") or null.</p>
    3208     *
    3209     * <pre>
    3210     * StringUtils.isAllEmpty(null)             = true
    3211     * StringUtils.isAllEmpty(null, "")         = true
    3212     * StringUtils.isAllEmpty(new String[] {})  = true
    3213     * StringUtils.isAllEmpty(null, "foo")      = false
    3214     * StringUtils.isAllEmpty("", "bar")        = false
    3215     * StringUtils.isAllEmpty("bob", "")        = false
    3216     * StringUtils.isAllEmpty("  bob  ", null)  = false
    3217     * StringUtils.isAllEmpty(" ", "bar")       = false
    3218     * StringUtils.isAllEmpty("foo", "bar")     = false
    3219     * </pre>
    3220     *
    3221     * @param css  the CharSequences to check, may be null or empty
    3222     * @return {@code true} if all of the CharSequences are empty or null
    3223     * @since 3.6
    3224     */
    3225    public static boolean isAllEmpty(final CharSequence... css) {
    3226        if (ArrayUtils.isEmpty(css)) {
    3227            return true;
    3228        }
    3229        for (final CharSequence cs : css) {
    3230            if (isNotEmpty(cs)) {
    3231                return false;
    3232            }
    3233        }
    3234        return true;
    3235    }
    3236
    3237    /**
    3238     * <p>Checks if the CharSequence contains only lowercase characters.</p>
    3239     *
    3240     * <p>{@code null} will return {@code false}.
    3241     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3242     *
    3243     * <pre>
    3244     * StringUtils.isAllLowerCase(null)   = false
    3245     * StringUtils.isAllLowerCase("")     = false
    3246     * StringUtils.isAllLowerCase("  ")   = false
    3247     * StringUtils.isAllLowerCase("abc")  = true
    3248     * StringUtils.isAllLowerCase("abC")  = false
    3249     * StringUtils.isAllLowerCase("ab c") = false
    3250     * StringUtils.isAllLowerCase("ab1c") = false
    3251     * StringUtils.isAllLowerCase("ab/c") = false
    3252     * </pre>
    3253     *
    3254     * @param cs  the CharSequence to check, may be null
    3255     * @return {@code true} if only contains lowercase characters, and is non-null
    3256     * @since 2.5
    3257     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    3258     */
    3259    public static boolean isAllLowerCase(final CharSequence cs) {
    3260        if (isEmpty(cs)) {
    3261            return false;
    3262        }
    3263        final int sz = cs.length();
    3264        for (int i = 0; i < sz; i++) {
    3265            if (!Character.isLowerCase(cs.charAt(i))) {
    3266                return false;
    3267            }
    3268        }
    3269        return true;
    3270    }
    3271
    3272    /**
    3273     * <p>Checks if the CharSequence contains only uppercase characters.</p>
    3274     *
    3275     * <p>{@code null} will return {@code false}.
    3276     * An empty String (length()=0) will return {@code false}.</p>
    3277     *
    3278     * <pre>
    3279     * StringUtils.isAllUpperCase(null)   = false
    3280     * StringUtils.isAllUpperCase("")     = false
    3281     * StringUtils.isAllUpperCase("  ")   = false
    3282     * StringUtils.isAllUpperCase("ABC")  = true
    3283     * StringUtils.isAllUpperCase("aBC")  = false
    3284     * StringUtils.isAllUpperCase("A C")  = false
    3285     * StringUtils.isAllUpperCase("A1C")  = false
    3286     * StringUtils.isAllUpperCase("A/C")  = false
    3287     * </pre>
    3288     *
    3289     * @param cs the CharSequence to check, may be null
    3290     * @return {@code true} if only contains uppercase characters, and is non-null
    3291     * @since 2.5
    3292     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    3293     */
    3294    public static boolean isAllUpperCase(final CharSequence cs) {
    3295        if (isEmpty(cs)) {
    3296            return false;
    3297        }
    3298        final int sz = cs.length();
    3299        for (int i = 0; i < sz; i++) {
    3300            if (!Character.isUpperCase(cs.charAt(i))) {
    3301                return false;
    3302            }
    3303        }
    3304        return true;
    3305    }
    3306
    3307    /**
    3308     * <p>Checks if the CharSequence contains only Unicode letters.</p>
    3309     *
    3310     * <p>{@code null} will return {@code false}.
    3311     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3312     *
    3313     * <pre>
    3314     * StringUtils.isAlpha(null)   = false
    3315     * StringUtils.isAlpha("")     = false
    3316     * StringUtils.isAlpha("  ")   = false
    3317     * StringUtils.isAlpha("abc")  = true
    3318     * StringUtils.isAlpha("ab2c") = false
    3319     * StringUtils.isAlpha("ab-c") = false
    3320     * </pre>
    3321     *
    3322     * @param cs  the CharSequence to check, may be null
    3323     * @return {@code true} if only contains letters, and is non-null
    3324     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    3325     * @since 3.0 Changed "" to return false and not true
    3326     */
    3327    public static boolean isAlpha(final CharSequence cs) {
    3328        if (isEmpty(cs)) {
    3329            return false;
    3330        }
    3331        final int sz = cs.length();
    3332        for (int i = 0; i < sz; i++) {
    3333            if (!Character.isLetter(cs.charAt(i))) {
    3334                return false;
    3335            }
    3336        }
    3337        return true;
    3338    }
    3339
    3340    /**
    3341     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
    3342     *
    3343     * <p>{@code null} will return {@code false}.
    3344     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3345     *
    3346     * <pre>
    3347     * StringUtils.isAlphanumeric(null)   = false
    3348     * StringUtils.isAlphanumeric("")     = false
    3349     * StringUtils.isAlphanumeric("  ")   = false
    3350     * StringUtils.isAlphanumeric("abc")  = true
    3351     * StringUtils.isAlphanumeric("ab c") = false
    3352     * StringUtils.isAlphanumeric("ab2c") = true
    3353     * StringUtils.isAlphanumeric("ab-c") = false
    3354     * </pre>
    3355     *
    3356     * @param cs  the CharSequence to check, may be null
    3357     * @return {@code true} if only contains letters or digits,
    3358     *  and is non-null
    3359     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    3360     * @since 3.0 Changed "" to return false and not true
    3361     */
    3362    public static boolean isAlphanumeric(final CharSequence cs) {
    3363        if (isEmpty(cs)) {
    3364            return false;
    3365        }
    3366        final int sz = cs.length();
    3367        for (int i = 0; i < sz; i++) {
    3368            if (!Character.isLetterOrDigit(cs.charAt(i))) {
    3369                return false;
    3370            }
    3371        }
    3372        return true;
    3373    }
    3374
    3375    /**
    3376     * <p>Checks if the CharSequence contains only Unicode letters, digits
    3377     * or space ({@code ' '}).</p>
    3378     *
    3379     * <p>{@code null} will return {@code false}.
    3380     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3381     *
    3382     * <pre>
    3383     * StringUtils.isAlphanumericSpace(null)   = false
    3384     * StringUtils.isAlphanumericSpace("")     = true
    3385     * StringUtils.isAlphanumericSpace("  ")   = true
    3386     * StringUtils.isAlphanumericSpace("abc")  = true
    3387     * StringUtils.isAlphanumericSpace("ab c") = true
    3388     * StringUtils.isAlphanumericSpace("ab2c") = true
    3389     * StringUtils.isAlphanumericSpace("ab-c") = false
    3390     * </pre>
    3391     *
    3392     * @param cs  the CharSequence to check, may be null
    3393     * @return {@code true} if only contains letters, digits or space,
    3394     *  and is non-null
    3395     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    3396     */
    3397    public static boolean isAlphanumericSpace(final CharSequence cs) {
    3398        if (cs == null) {
    3399            return false;
    3400        }
    3401        final int sz = cs.length();
    3402        for (int i = 0; i < sz; i++) {
    3403            final char nowChar = cs.charAt(i);
    3404            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) {
    3405                return false;
    3406            }
    3407        }
    3408        return true;
    3409    }
    3410
    3411    /**
    3412     * <p>Checks if the CharSequence contains only Unicode letters and
    3413     * space (' ').</p>
    3414     *
    3415     * <p>{@code null} will return {@code false}
    3416     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3417     *
    3418     * <pre>
    3419     * StringUtils.isAlphaSpace(null)   = false
    3420     * StringUtils.isAlphaSpace("")     = true
    3421     * StringUtils.isAlphaSpace("  ")   = true
    3422     * StringUtils.isAlphaSpace("abc")  = true
    3423     * StringUtils.isAlphaSpace("ab c") = true
    3424     * StringUtils.isAlphaSpace("ab2c") = false
    3425     * StringUtils.isAlphaSpace("ab-c") = false
    3426     * </pre>
    3427     *
    3428     * @param cs  the CharSequence to check, may be null
    3429     * @return {@code true} if only contains letters and space,
    3430     *  and is non-null
    3431     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    3432     */
    3433    public static boolean isAlphaSpace(final CharSequence cs) {
    3434        if (cs == null) {
    3435            return false;
    3436        }
    3437        final int sz = cs.length();
    3438        for (int i = 0; i < sz; i++) {
    3439            final char nowChar = cs.charAt(i);
    3440            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
    3441                return false;
    3442            }
    3443        }
    3444        return true;
    3445    }
    3446
    3447    /**
    3448     * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p>
    3449     *
    3450     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3451     *
    3452     * <pre>
    3453     * StringUtils.isAnyBlank((String) null)    = true
    3454     * StringUtils.isAnyBlank((String[]) null)  = false
    3455     * StringUtils.isAnyBlank(null, "foo")      = true
    3456     * StringUtils.isAnyBlank(null, null)       = true
    3457     * StringUtils.isAnyBlank("", "bar")        = true
    3458     * StringUtils.isAnyBlank("bob", "")        = true
    3459     * StringUtils.isAnyBlank("  bob  ", null)  = true
    3460     * StringUtils.isAnyBlank(" ", "bar")       = true
    3461     * StringUtils.isAnyBlank(new String[] {})  = false
    3462     * StringUtils.isAnyBlank(new String[]{""}) = true
    3463     * StringUtils.isAnyBlank("foo", "bar")     = false
    3464     * </pre>
    3465     *
    3466     * @param css  the CharSequences to check, may be null or empty
    3467     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
    3468     * @since 3.2
    3469     */
    3470    public static boolean isAnyBlank(final CharSequence... css) {
    3471        if (ArrayUtils.isEmpty(css)) {
    3472            return false;
    3473        }
    3474        for (final CharSequence cs : css) {
    3475            if (isBlank(cs)) {
    3476                return true;
    3477            }
    3478        }
    3479        return false;
    3480    }
    3481
    3482    /**
    3483     * <p>Checks if any of the CharSequences are empty ("") or null.</p>
    3484     *
    3485     * <pre>
    3486     * StringUtils.isAnyEmpty((String) null)    = true
    3487     * StringUtils.isAnyEmpty((String[]) null)  = false
    3488     * StringUtils.isAnyEmpty(null, "foo")      = true
    3489     * StringUtils.isAnyEmpty("", "bar")        = true
    3490     * StringUtils.isAnyEmpty("bob", "")        = true
    3491     * StringUtils.isAnyEmpty("  bob  ", null)  = true
    3492     * StringUtils.isAnyEmpty(" ", "bar")       = false
    3493     * StringUtils.isAnyEmpty("foo", "bar")     = false
    3494     * StringUtils.isAnyEmpty(new String[]{})   = false
    3495     * StringUtils.isAnyEmpty(new String[]{""}) = true
    3496     * </pre>
    3497     *
    3498     * @param css  the CharSequences to check, may be null or empty
    3499     * @return {@code true} if any of the CharSequences are empty or null
    3500     * @since 3.2
    3501     */
    3502    public static boolean isAnyEmpty(final CharSequence... css) {
    3503        if (ArrayUtils.isEmpty(css)) {
    3504            return false;
    3505        }
    3506        for (final CharSequence cs : css) {
    3507            if (isEmpty(cs)) {
    3508                return true;
    3509            }
    3510        }
    3511        return false;
    3512    }
    3513
    3514    /**
    3515     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
    3516     *
    3517     * <p>{@code null} will return {@code false}.
    3518     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3519     *
    3520     * <pre>
    3521     * StringUtils.isAsciiPrintable(null)     = false
    3522     * StringUtils.isAsciiPrintable("")       = true
    3523     * StringUtils.isAsciiPrintable(" ")      = true
    3524     * StringUtils.isAsciiPrintable("Ceki")   = true
    3525     * StringUtils.isAsciiPrintable("ab2c")   = true
    3526     * StringUtils.isAsciiPrintable("!ab-c~") = true
    3527     * StringUtils.isAsciiPrintable("\u0020") = true
    3528     * StringUtils.isAsciiPrintable("\u0021") = true
    3529     * StringUtils.isAsciiPrintable("\u007e") = true
    3530     * StringUtils.isAsciiPrintable("\u007f") = false
    3531     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    3532     * </pre>
    3533     *
    3534     * @param cs the CharSequence to check, may be null
    3535     * @return {@code true} if every character is in the range
    3536     *  32 thru 126
    3537     * @since 2.1
    3538     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    3539     */
    3540    public static boolean isAsciiPrintable(final CharSequence cs) {
    3541        if (cs == null) {
    3542            return false;
    3543        }
    3544        final int sz = cs.length();
    3545        for (int i = 0; i < sz; i++) {
    3546            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
    3547                return false;
    3548            }
    3549        }
    3550        return true;
    3551    }
    3552
    3553    /**
    3554     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
    3555     *
    3556     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3557     *
    3558     * <pre>
    3559     * StringUtils.isBlank(null)      = true
    3560     * StringUtils.isBlank("")        = true
    3561     * StringUtils.isBlank(" ")       = true
    3562     * StringUtils.isBlank("bob")     = false
    3563     * StringUtils.isBlank("  bob  ") = false
    3564     * </pre>
    3565     *
    3566     * @param cs  the CharSequence to check, may be null
    3567     * @return {@code true} if the CharSequence is null, empty or whitespace only
    3568     * @since 2.0
    3569     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    3570     */
    3571    public static boolean isBlank(final CharSequence cs) {
    3572        final int strLen = length(cs);
    3573        if (strLen == 0) {
    3574            return true;
    3575        }
    3576        for (int i = 0; i < strLen; i++) {
    3577            if (!Character.isWhitespace(cs.charAt(i))) {
    3578                return false;
    3579            }
    3580        }
    3581        return true;
    3582    }
    3583
    3584    /**
    3585     * <p>Checks if a CharSequence is empty ("") or null.</p>
    3586     *
    3587     * <pre>
    3588     * StringUtils.isEmpty(null)      = true
    3589     * StringUtils.isEmpty("")        = true
    3590     * StringUtils.isEmpty(" ")       = false
    3591     * StringUtils.isEmpty("bob")     = false
    3592     * StringUtils.isEmpty("  bob  ") = false
    3593     * </pre>
    3594     *
    3595     * <p>NOTE: This method changed in Lang version 2.0.
    3596     * It no longer trims the CharSequence.
    3597     * That functionality is available in isBlank().</p>
    3598     *
    3599     * @param cs  the CharSequence to check, may be null
    3600     * @return {@code true} if the CharSequence is empty or null
    3601     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    3602     */
    3603    public static boolean isEmpty(final CharSequence cs) {
    3604        return cs == null || cs.length() == 0;
    3605    }
    3606
    3607    /**
    3608     * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p>
    3609     *
    3610     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
    3611     * {@code false}.</p>
    3612     *
    3613     * <pre>
    3614     * StringUtils.isMixedCase(null)    = false
    3615     * StringUtils.isMixedCase("")      = false
    3616     * StringUtils.isMixedCase("ABC")   = false
    3617     * StringUtils.isMixedCase("abc")   = false
    3618     * StringUtils.isMixedCase("aBc")   = true
    3619     * StringUtils.isMixedCase("A c")   = true
    3620     * StringUtils.isMixedCase("A1c")   = true
    3621     * StringUtils.isMixedCase("a/C")   = true
    3622     * StringUtils.isMixedCase("aC\t")  = true
    3623     * </pre>
    3624     *
    3625     * @param cs the CharSequence to check, may be null
    3626     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
    3627     * @since 3.5
    3628     */
    3629    public static boolean isMixedCase(final CharSequence cs) {
    3630        if (isEmpty(cs) || cs.length() == 1) {
    3631            return false;
    3632        }
    3633        boolean containsUppercase = false;
    3634        boolean containsLowercase = false;
    3635        final int sz = cs.length();
    3636        for (int i = 0; i < sz; i++) {
    3637            if (containsUppercase && containsLowercase) {
    3638                return true;
    3639            } else if (Character.isUpperCase(cs.charAt(i))) {
    3640                containsUppercase = true;
    3641            } else if (Character.isLowerCase(cs.charAt(i))) {
    3642                containsLowercase = true;
    3643            }
    3644        }
    3645        return containsUppercase && containsLowercase;
    3646    }
    3647
    3648    /**
    3649     * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p>
    3650     *
    3651     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3652     *
    3653     * <pre>
    3654     * StringUtils.isNoneBlank((String) null)    = false
    3655     * StringUtils.isNoneBlank((String[]) null)  = true
    3656     * StringUtils.isNoneBlank(null, "foo")      = false
    3657     * StringUtils.isNoneBlank(null, null)       = false
    3658     * StringUtils.isNoneBlank("", "bar")        = false
    3659     * StringUtils.isNoneBlank("bob", "")        = false
    3660     * StringUtils.isNoneBlank("  bob  ", null)  = false
    3661     * StringUtils.isNoneBlank(" ", "bar")       = false
    3662     * StringUtils.isNoneBlank(new String[] {})  = true
    3663     * StringUtils.isNoneBlank(new String[]{""}) = false
    3664     * StringUtils.isNoneBlank("foo", "bar")     = true
    3665     * </pre>
    3666     *
    3667     * @param css  the CharSequences to check, may be null or empty
    3668     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
    3669     * @since 3.2
    3670     */
    3671    public static boolean isNoneBlank(final CharSequence... css) {
    3672      return !isAnyBlank(css);
    3673    }
    3674
    3675    /**
    3676     * <p>Checks if none of the CharSequences are empty ("") or null.</p>
    3677     *
    3678     * <pre>
    3679     * StringUtils.isNoneEmpty((String) null)    = false
    3680     * StringUtils.isNoneEmpty((String[]) null)  = true
    3681     * StringUtils.isNoneEmpty(null, "foo")      = false
    3682     * StringUtils.isNoneEmpty("", "bar")        = false
    3683     * StringUtils.isNoneEmpty("bob", "")        = false
    3684     * StringUtils.isNoneEmpty("  bob  ", null)  = false
    3685     * StringUtils.isNoneEmpty(new String[] {})  = true
    3686     * StringUtils.isNoneEmpty(new String[]{""}) = false
    3687     * StringUtils.isNoneEmpty(" ", "bar")       = true
    3688     * StringUtils.isNoneEmpty("foo", "bar")     = true
    3689     * </pre>
    3690     *
    3691     * @param css  the CharSequences to check, may be null or empty
    3692     * @return {@code true} if none of the CharSequences are empty or null
    3693     * @since 3.2
    3694     */
    3695    public static boolean isNoneEmpty(final CharSequence... css) {
    3696      return !isAnyEmpty(css);
    3697    }
    3698
    3699    /**
    3700     * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
    3701     *
    3702     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3703     *
    3704     * <pre>
    3705     * StringUtils.isNotBlank(null)      = false
    3706     * StringUtils.isNotBlank("")        = false
    3707     * StringUtils.isNotBlank(" ")       = false
    3708     * StringUtils.isNotBlank("bob")     = true
    3709     * StringUtils.isNotBlank("  bob  ") = true
    3710     * </pre>
    3711     *
    3712     * @param cs  the CharSequence to check, may be null
    3713     * @return {@code true} if the CharSequence is
    3714     *  not empty and not null and not whitespace only
    3715     * @since 2.0
    3716     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    3717     */
    3718    public static boolean isNotBlank(final CharSequence cs) {
    3719        return !isBlank(cs);
    3720    }
    3721
    3722    /**
    3723     * <p>Checks if a CharSequence is not empty ("") and not null.</p>
    3724     *
    3725     * <pre>
    3726     * StringUtils.isNotEmpty(null)      = false
    3727     * StringUtils.isNotEmpty("")        = false
    3728     * StringUtils.isNotEmpty(" ")       = true
    3729     * StringUtils.isNotEmpty("bob")     = true
    3730     * StringUtils.isNotEmpty("  bob  ") = true
    3731     * </pre>
    3732     *
    3733     * @param cs  the CharSequence to check, may be null
    3734     * @return {@code true} if the CharSequence is not empty and not null
    3735     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    3736     */
    3737    public static boolean isNotEmpty(final CharSequence cs) {
    3738        return !isEmpty(cs);
    3739    }
    3740
    3741    /**
    3742     * <p>Checks if the CharSequence contains only Unicode digits.
    3743     * A decimal point is not a Unicode digit and returns false.</p>
    3744     *
    3745     * <p>{@code null} will return {@code false}.
    3746     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3747     *
    3748     * <p>Note that the method does not allow for a leading sign, either positive or negative.
    3749     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
    3750     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
    3751     * for int or long respectively.</p>
    3752     *
    3753     * <pre>
    3754     * StringUtils.isNumeric(null)   = false
    3755     * StringUtils.isNumeric("")     = false
    3756     * StringUtils.isNumeric("  ")   = false
    3757     * StringUtils.isNumeric("123")  = true
    3758     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    3759     * StringUtils.isNumeric("12 3") = false
    3760     * StringUtils.isNumeric("ab2c") = false
    3761     * StringUtils.isNumeric("12-3") = false
    3762     * StringUtils.isNumeric("12.3") = false
    3763     * StringUtils.isNumeric("-123") = false
    3764     * StringUtils.isNumeric("+123") = false
    3765     * </pre>
    3766     *
    3767     * @param cs  the CharSequence to check, may be null
    3768     * @return {@code true} if only contains digits, and is non-null
    3769     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    3770     * @since 3.0 Changed "" to return false and not true
    3771     */
    3772    public static boolean isNumeric(final CharSequence cs) {
    3773        if (isEmpty(cs)) {
    3774            return false;
    3775        }
    3776        final int sz = cs.length();
    3777        for (int i = 0; i < sz; i++) {
    3778            if (!Character.isDigit(cs.charAt(i))) {
    3779                return false;
    3780            }
    3781        }
    3782        return true;
    3783    }
    3784
    3785    /**
    3786     * <p>Checks if the CharSequence contains only Unicode digits or space
    3787     * ({@code ' '}).
    3788     * A decimal point is not a Unicode digit and returns false.</p>
    3789     *
    3790     * <p>{@code null} will return {@code false}.
    3791     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3792     *
    3793     * <pre>
    3794     * StringUtils.isNumericSpace(null)   = false
    3795     * StringUtils.isNumericSpace("")     = true
    3796     * StringUtils.isNumericSpace("  ")   = true
    3797     * StringUtils.isNumericSpace("123")  = true
    3798     * StringUtils.isNumericSpace("12 3") = true
    3799     * StringUtils.isNumericSpace("\u0967\u0968\u0969")  = true
    3800     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
    3801     * StringUtils.isNumericSpace("ab2c") = false
    3802     * StringUtils.isNumericSpace("12-3") = false
    3803     * StringUtils.isNumericSpace("12.3") = false
    3804     * </pre>
    3805     *
    3806     * @param cs  the CharSequence to check, may be null
    3807     * @return {@code true} if only contains digits or space,
    3808     *  and is non-null
    3809     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    3810     */
    3811    public static boolean isNumericSpace(final CharSequence cs) {
    3812        if (cs == null) {
    3813            return false;
    3814        }
    3815        final int sz = cs.length();
    3816        for (int i = 0; i < sz; i++) {
    3817            final char nowChar = cs.charAt(i);
    3818            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
    3819                return false;
    3820            }
    3821        }
    3822        return true;
    3823    }
    3824
    3825    /**
    3826     * <p>Checks if the CharSequence contains only whitespace.</p>
    3827     *
    3828     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3829     *
    3830     * <p>{@code null} will return {@code false}.
    3831     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3832     *
    3833     * <pre>
    3834     * StringUtils.isWhitespace(null)   = false
    3835     * StringUtils.isWhitespace("")     = true
    3836     * StringUtils.isWhitespace("  ")   = true
    3837     * StringUtils.isWhitespace("abc")  = false
    3838     * StringUtils.isWhitespace("ab2c") = false
    3839     * StringUtils.isWhitespace("ab-c") = false
    3840     * </pre>
    3841     *
    3842     * @param cs  the CharSequence to check, may be null
    3843     * @return {@code true} if only contains whitespace, and is non-null
    3844     * @since 2.0
    3845     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    3846     */
    3847    public static boolean isWhitespace(final CharSequence cs) {
    3848        if (cs == null) {
    3849            return false;
    3850        }
    3851        final int sz = cs.length();
    3852        for (int i = 0; i < sz; i++) {
    3853            if (!Character.isWhitespace(cs.charAt(i))) {
    3854                return false;
    3855            }
    3856        }
    3857        return true;
    3858    }
    3859
    3860    /**
    3861     * <p>
    3862     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3863     * </p>
    3864     *
    3865     * <p>
    3866     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3867     * by empty strings.
    3868     * </p>
    3869     *
    3870     * <pre>
    3871     * StringUtils.join(null, *)              = null
    3872     * StringUtils.join([], *)                = ""
    3873     * StringUtils.join([null], *)            = ""
    3874     * StringUtils.join([false, false], ';')  = "false;false"
    3875     * </pre>
    3876     *
    3877     * @param array
    3878     *            the array of values to join together, may be null
    3879     * @param delimiter
    3880     *            the separator character to use
    3881     * @return the joined String, {@code null} if null array input
    3882     * @since 3.12.0
    3883     */
    3884    public static String join(final boolean[] array, final char delimiter) {
    3885        if (array == null) {
    3886            return null;
    3887        }
    3888        return join(array, delimiter, 0, array.length);
    3889    }
    3890
    3891    /**
    3892     * <p>
    3893     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3894     * </p>
    3895     *
    3896     * <p>
    3897     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3898     * by empty strings.
    3899     * </p>
    3900     *
    3901     * <pre>
    3902     * StringUtils.join(null, *)                   = null
    3903     * StringUtils.join([], *)                     = ""
    3904     * StringUtils.join([null], *)                 = ""
    3905     * StringUtils.join([true, false, true], ';')  = "true;false;true"
    3906     * </pre>
    3907     *
    3908     * @param array
    3909     *            the array of values to join together, may be null
    3910     * @param delimiter
    3911     *            the separator character to use
    3912     * @param startIndex
    3913     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3914     *            array
    3915     * @param endIndex
    3916     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3917     *            the array
    3918     * @return the joined String, {@code null} if null array input
    3919     * @since 3.12.0
    3920     */
    3921    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
    3922        if (array == null) {
    3923            return null;
    3924        }
    3925        if (endIndex - startIndex <= 0) {
    3926            return EMPTY;
    3927        }
    3928        final StringJoiner joiner = newStringJoiner(delimiter);
    3929        for (int i = startIndex; i < endIndex; i++) {
    3930            joiner.add(String.valueOf(array[i]));
    3931        }
    3932        return joiner.toString();
    3933    }
    3934
    3935    /**
    3936     * <p>
    3937     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3938     * </p>
    3939     *
    3940     * <p>
    3941     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3942     * by empty strings.
    3943     * </p>
    3944     *
    3945     * <pre>
    3946     * StringUtils.join(null, *)               = null
    3947     * StringUtils.join([], *)                 = ""
    3948     * StringUtils.join([null], *)             = ""
    3949     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3950     * StringUtils.join([1, 2, 3], null) = "123"
    3951     * </pre>
    3952     *
    3953     * @param array
    3954     *            the array of values to join together, may be null
    3955     * @param delimiter
    3956     *            the separator character to use
    3957     * @return the joined String, {@code null} if null array input
    3958     * @since 3.2
    3959     */
    3960    public static String join(final byte[] array, final char delimiter) {
    3961        if (array == null) {
    3962            return null;
    3963        }
    3964        return join(array, delimiter, 0, array.length);
    3965    }
    3966
    3967    /**
    3968     * <p>
    3969     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3970     * </p>
    3971     *
    3972     * <p>
    3973     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3974     * by empty strings.
    3975     * </p>
    3976     *
    3977     * <pre>
    3978     * StringUtils.join(null, *)               = null
    3979     * StringUtils.join([], *)                 = ""
    3980     * StringUtils.join([null], *)             = ""
    3981     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3982     * StringUtils.join([1, 2, 3], null) = "123"
    3983     * </pre>
    3984     *
    3985     * @param array
    3986     *            the array of values to join together, may be null
    3987     * @param delimiter
    3988     *            the separator character to use
    3989     * @param startIndex
    3990     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3991     *            array
    3992     * @param endIndex
    3993     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3994     *            the array
    3995     * @return the joined String, {@code null} if null array input
    3996     * @since 3.2
    3997     */
    3998    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
    3999        if (array == null) {
    4000            return null;
    4001        }
    4002        if (endIndex - startIndex <= 0) {
    4003            return EMPTY;
    4004        }
    4005        final StringJoiner joiner = newStringJoiner(delimiter);
    4006        for (int i = startIndex; i < endIndex; i++) {
    4007            joiner.add(String.valueOf(array[i]));
    4008        }
    4009        return joiner.toString();
    4010    }
    4011
    4012    /**
    4013     * <p>
    4014     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4015     * </p>
    4016     *
    4017     * <p>
    4018     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4019     * by empty strings.
    4020     * </p>
    4021     *
    4022     * <pre>
    4023     * StringUtils.join(null, *)               = null
    4024     * StringUtils.join([], *)                 = ""
    4025     * StringUtils.join([null], *)             = ""
    4026     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4027     * StringUtils.join([1, 2, 3], null) = "123"
    4028     * </pre>
    4029     *
    4030     * @param array
    4031     *            the array of values to join together, may be null
    4032     * @param delimiter
    4033     *            the separator character to use
    4034     * @return the joined String, {@code null} if null array input
    4035     * @since 3.2
    4036     */
    4037    public static String join(final char[] array, final char delimiter) {
    4038        if (array == null) {
    4039            return null;
    4040        }
    4041        return join(array, delimiter, 0, array.length);
    4042    }
    4043
    4044    /**
    4045     * <p>
    4046     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4047     * </p>
    4048     *
    4049     * <p>
    4050     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4051     * by empty strings.
    4052     * </p>
    4053     *
    4054     * <pre>
    4055     * StringUtils.join(null, *)               = null
    4056     * StringUtils.join([], *)                 = ""
    4057     * StringUtils.join([null], *)             = ""
    4058     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4059     * StringUtils.join([1, 2, 3], null) = "123"
    4060     * </pre>
    4061     *
    4062     * @param array
    4063     *            the array of values to join together, may be null
    4064     * @param delimiter
    4065     *            the separator character to use
    4066     * @param startIndex
    4067     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4068     *            array
    4069     * @param endIndex
    4070     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4071     *            the array
    4072     * @return the joined String, {@code null} if null array input
    4073     * @since 3.2
    4074     */
    4075    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
    4076        if (array == null) {
    4077            return null;
    4078        }
    4079        if (endIndex - startIndex <= 0) {
    4080            return EMPTY;
    4081        }
    4082        final StringJoiner joiner = newStringJoiner(delimiter);
    4083        for (int i = startIndex; i < endIndex; i++) {
    4084            joiner.add(String.valueOf(array[i]));
    4085        }
    4086        return joiner.toString();
    4087    }
    4088
    4089    /**
    4090     * <p>
    4091     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4092     * </p>
    4093     *
    4094     * <p>
    4095     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4096     * by empty strings.
    4097     * </p>
    4098     *
    4099     * <pre>
    4100     * StringUtils.join(null, *)               = null
    4101     * StringUtils.join([], *)                 = ""
    4102     * StringUtils.join([null], *)             = ""
    4103     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4104     * StringUtils.join([1, 2, 3], null) = "123"
    4105     * </pre>
    4106     *
    4107     * @param array
    4108     *            the array of values to join together, may be null
    4109     * @param delimiter
    4110     *            the separator character to use
    4111     * @return the joined String, {@code null} if null array input
    4112     * @since 3.2
    4113     */
    4114    public static String join(final double[] array, final char delimiter) {
    4115        if (array == null) {
    4116            return null;
    4117        }
    4118        return join(array, delimiter, 0, array.length);
    4119    }
    4120
    4121    /**
    4122     * <p>
    4123     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4124     * </p>
    4125     *
    4126     * <p>
    4127     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4128     * by empty strings.
    4129     * </p>
    4130     *
    4131     * <pre>
    4132     * StringUtils.join(null, *)               = null
    4133     * StringUtils.join([], *)                 = ""
    4134     * StringUtils.join([null], *)             = ""
    4135     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4136     * StringUtils.join([1, 2, 3], null) = "123"
    4137     * </pre>
    4138     *
    4139     * @param array
    4140     *            the array of values to join together, may be null
    4141     * @param delimiter
    4142     *            the separator character to use
    4143     * @param startIndex
    4144     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4145     *            array
    4146     * @param endIndex
    4147     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4148     *            the array
    4149     * @return the joined String, {@code null} if null array input
    4150     * @since 3.2
    4151     */
    4152    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
    4153        if (array == null) {
    4154            return null;
    4155        }
    4156        if (endIndex - startIndex <= 0) {
    4157            return EMPTY;
    4158        }
    4159        final StringJoiner joiner = newStringJoiner(delimiter);
    4160        for (int i = startIndex; i < endIndex; i++) {
    4161            joiner.add(String.valueOf(array[i]));
    4162        }
    4163        return joiner.toString();
    4164    }
    4165
    4166    /**
    4167     * <p>
    4168     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4169     * </p>
    4170     *
    4171     * <p>
    4172     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4173     * by empty strings.
    4174     * </p>
    4175     *
    4176     * <pre>
    4177     * StringUtils.join(null, *)               = null
    4178     * StringUtils.join([], *)                 = ""
    4179     * StringUtils.join([null], *)             = ""
    4180     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4181     * StringUtils.join([1, 2, 3], null) = "123"
    4182     * </pre>
    4183     *
    4184     * @param array
    4185     *            the array of values to join together, may be null
    4186     * @param delimiter
    4187     *            the separator character to use
    4188     * @return the joined String, {@code null} if null array input
    4189     * @since 3.2
    4190     */
    4191    public static String join(final float[] array, final char delimiter) {
    4192        if (array == null) {
    4193            return null;
    4194        }
    4195        return join(array, delimiter, 0, array.length);
    4196    }
    4197
    4198    /**
    4199     * <p>
    4200     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4201     * </p>
    4202     *
    4203     * <p>
    4204     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4205     * by empty strings.
    4206     * </p>
    4207     *
    4208     * <pre>
    4209     * StringUtils.join(null, *)               = null
    4210     * StringUtils.join([], *)                 = ""
    4211     * StringUtils.join([null], *)             = ""
    4212     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4213     * StringUtils.join([1, 2, 3], null) = "123"
    4214     * </pre>
    4215     *
    4216     * @param array
    4217     *            the array of values to join together, may be null
    4218     * @param delimiter
    4219     *            the separator character to use
    4220     * @param startIndex
    4221     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4222     *            array
    4223     * @param endIndex
    4224     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4225     *            the array
    4226     * @return the joined String, {@code null} if null array input
    4227     * @since 3.2
    4228     */
    4229    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
    4230        if (array == null) {
    4231            return null;
    4232        }
    4233        if (endIndex - startIndex <= 0) {
    4234            return EMPTY;
    4235        }
    4236        final StringJoiner joiner = newStringJoiner(delimiter);
    4237        for (int i = startIndex; i < endIndex; i++) {
    4238            joiner.add(String.valueOf(array[i]));
    4239        }
    4240        return joiner.toString();
    4241    }
    4242
    4243    /**
    4244     * <p>
    4245     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4246     * </p>
    4247     *
    4248     * <p>
    4249     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4250     * by empty strings.
    4251     * </p>
    4252     *
    4253     * <pre>
    4254     * StringUtils.join(null, *)               = null
    4255     * StringUtils.join([], *)                 = ""
    4256     * StringUtils.join([null], *)             = ""
    4257     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4258     * StringUtils.join([1, 2, 3], null) = "123"
    4259     * </pre>
    4260     *
    4261     * @param array
    4262     *            the array of values to join together, may be null
    4263     * @param separator
    4264     *            the separator character to use
    4265     * @return the joined String, {@code null} if null array input
    4266     * @since 3.2
    4267     */
    4268    public static String join(final int[] array, final char separator) {
    4269        if (array == null) {
    4270            return null;
    4271        }
    4272        return join(array, separator, 0, array.length);
    4273    }
    4274
    4275    /**
    4276     * <p>
    4277     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4278     * </p>
    4279     *
    4280     * <p>
    4281     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4282     * by empty strings.
    4283     * </p>
    4284     *
    4285     * <pre>
    4286     * StringUtils.join(null, *)               = null
    4287     * StringUtils.join([], *)                 = ""
    4288     * StringUtils.join([null], *)             = ""
    4289     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4290     * StringUtils.join([1, 2, 3], null) = "123"
    4291     * </pre>
    4292     *
    4293     * @param array
    4294     *            the array of values to join together, may be null
    4295     * @param delimiter
    4296     *            the separator character to use
    4297     * @param startIndex
    4298     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4299     *            array
    4300     * @param endIndex
    4301     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4302     *            the array
    4303     * @return the joined String, {@code null} if null array input
    4304     * @since 3.2
    4305     */
    4306    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
    4307        if (array == null) {
    4308            return null;
    4309        }
    4310        if (endIndex - startIndex <= 0) {
    4311            return EMPTY;
    4312        }
    4313        final StringJoiner joiner = newStringJoiner(delimiter);
    4314        for (int i = startIndex; i < endIndex; i++) {
    4315            joiner.add(String.valueOf(array[i]));
    4316        }
    4317        return joiner.toString();
    4318    }
    4319
    4320    /**
    4321     * <p>Joins the elements of the provided {@code Iterable} into
    4322     * a single String containing the provided elements.</p>
    4323     *
    4324     * <p>No delimiter is added before or after the list. Null objects or empty
    4325     * strings within the iteration are represented by empty strings.</p>
    4326     *
    4327     * <p>See the examples here: {@link #join(Object[],char)}. </p>
    4328     *
    4329     * @param iterable  the {@code Iterable} providing the values to join together, may be null
    4330     * @param separator  the separator character to use
    4331     * @return the joined String, {@code null} if null iterator input
    4332     * @since 2.3
    4333     */
    4334    public static String join(final Iterable<?> iterable, final char separator) {
    4335        if (iterable == null) {
    4336            return null;
    4337        }
    4338        return join(iterable.iterator(), separator);
    4339    }
    4340
    4341    /**
    4342     * <p>Joins the elements of the provided {@code Iterable} into
    4343     * a single String containing the provided elements.</p>
    4344     *
    4345     * <p>No delimiter is added before or after the list.
    4346     * A {@code null} separator is the same as an empty String ("").</p>
    4347     *
    4348     * <p>See the examples here: {@link #join(Object[],String)}. </p>
    4349     *
    4350     * @param iterable  the {@code Iterable} providing the values to join together, may be null
    4351     * @param separator  the separator character to use, null treated as ""
    4352     * @return the joined String, {@code null} if null iterator input
    4353     * @since 2.3
    4354     */
    4355    public static String join(final Iterable<?> iterable, final String separator) {
    4356        if (iterable == null) {
    4357            return null;
    4358        }
    4359        return join(iterable.iterator(), separator);
    4360    }
    4361
    4362    /**
    4363     * <p>Joins the elements of the provided {@code Iterator} into
    4364     * a single String containing the provided elements.</p>
    4365     *
    4366     * <p>No delimiter is added before or after the list. Null objects or empty
    4367     * strings within the iteration are represented by empty strings.</p>
    4368     *
    4369     * <p>See the examples here: {@link #join(Object[],char)}. </p>
    4370     *
    4371     * @param iterator  the {@code Iterator} of values to join together, may be null
    4372     * @param separator  the separator character to use
    4373     * @return the joined String, {@code null} if null iterator input
    4374     * @since 2.0
    4375     */
    4376    public static String join(final Iterator<?> iterator, final char separator) {
    4377
    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        final Object first = iterator.next();
    4386        if (!iterator.hasNext()) {
    4387            return toStringOrEmpty(first);
    4388        }
    4389
    4390        // two or more elements
    4391        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
    4392        if (first != null) {
    4393            buf.append(first);
    4394        }
    4395
    4396        while (iterator.hasNext()) {
    4397            buf.append(separator);
    4398            final Object obj = iterator.next();
    4399            if (obj != null) {
    4400                buf.append(obj);
    4401            }
    4402        }
    4403
    4404        return buf.toString();
    4405    }
    4406
    4407    /**
    4408     * <p>Joins the elements of the provided {@code Iterator} into
    4409     * a single String containing the provided elements.</p>
    4410     *
    4411     * <p>No delimiter is added before or after the list.
    4412     * A {@code null} separator is the same as an empty String ("").</p>
    4413     *
    4414     * <p>See the examples here: {@link #join(Object[],String)}. </p>
    4415     *
    4416     * @param iterator  the {@code Iterator} of values to join together, may be null
    4417     * @param separator  the separator character to use, null treated as ""
    4418     * @return the joined String, {@code null} if null iterator input
    4419     */
    4420    public static String join(final Iterator<?> iterator, final String separator) {
    4421
    4422        // handle null, zero and one elements before building a buffer
    4423        if (iterator == null) {
    4424            return null;
    4425        }
    4426        if (!iterator.hasNext()) {
    4427            return EMPTY;
    4428        }
    4429        final Object first = iterator.next();
    4430        if (!iterator.hasNext()) {
    4431            return Objects.toString(first, "");
    4432        }
    4433
    4434        // two or more elements
    4435        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
    4436        if (first != null) {
    4437            buf.append(first);
    4438        }
    4439
    4440        while (iterator.hasNext()) {
    4441            if (separator != null) {
    4442                buf.append(separator);
    4443            }
    4444            final Object obj = iterator.next();
    4445            if (obj != null) {
    4446                buf.append(obj);
    4447            }
    4448        }
    4449        return buf.toString();
    4450    }
    4451
    4452    /**
    4453     * <p>Joins the elements of the provided {@code List} into a single String
    4454     * containing the provided list of elements.</p>
    4455     *
    4456     * <p>No delimiter is added before or after the list.
    4457     * Null objects or empty strings within the array are represented by
    4458     * empty strings.</p>
    4459     *
    4460     * <pre>
    4461     * StringUtils.join(null, *)               = null
    4462     * StringUtils.join([], *)                 = ""
    4463     * StringUtils.join([null], *)             = ""
    4464     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4465     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4466     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4467     * </pre>
    4468     *
    4469     * @param list  the {@code List} of values to join together, may be null
    4470     * @param separator  the separator character to use
    4471     * @param startIndex the first index to start joining from.  It is
    4472     * an error to pass in a start index past the end of the list
    4473     * @param endIndex the index to stop joining from (exclusive). It is
    4474     * an error to pass in an end index past the end of the list
    4475     * @return the joined String, {@code null} if null list input
    4476     * @since 3.8
    4477     */
    4478    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
    4479        if (list == null) {
    4480            return null;
    4481        }
    4482        final int noOfItems = endIndex - startIndex;
    4483        if (noOfItems <= 0) {
    4484            return EMPTY;
    4485        }
    4486        final List<?> subList = list.subList(startIndex, endIndex);
    4487        return join(subList.iterator(), separator);
    4488    }
    4489
    4490    /**
    4491     * <p>Joins the elements of the provided {@code List} into a single String
    4492     * containing the provided list of elements.</p>
    4493     *
    4494     * <p>No delimiter is added before or after the list.
    4495     * Null objects or empty strings within the array are represented by
    4496     * empty strings.</p>
    4497     *
    4498     * <pre>
    4499     * StringUtils.join(null, *)               = null
    4500     * StringUtils.join([], *)                 = ""
    4501     * StringUtils.join([null], *)             = ""
    4502     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4503     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4504     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4505     * </pre>
    4506     *
    4507     * @param list  the {@code List} of values to join together, may be null
    4508     * @param separator  the separator character to use
    4509     * @param startIndex the first index to start joining from.  It is
    4510     * an error to pass in a start index past the end of the list
    4511     * @param endIndex the index to stop joining from (exclusive). It is
    4512     * an error to pass in an end index past the end of the list
    4513     * @return the joined String, {@code null} if null list input
    4514     * @since 3.8
    4515     */
    4516    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
    4517        if (list == null) {
    4518            return null;
    4519        }
    4520        final int noOfItems = endIndex - startIndex;
    4521        if (noOfItems <= 0) {
    4522            return EMPTY;
    4523        }
    4524        final List<?> subList = list.subList(startIndex, endIndex);
    4525        return join(subList.iterator(), separator);
    4526    }
    4527
    4528
    4529    /**
    4530     * <p>
    4531     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4532     * </p>
    4533     *
    4534     * <p>
    4535     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4536     * by empty strings.
    4537     * </p>
    4538     *
    4539     * <pre>
    4540     * StringUtils.join(null, *)               = null
    4541     * StringUtils.join([], *)                 = ""
    4542     * StringUtils.join([null], *)             = ""
    4543     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4544     * StringUtils.join([1, 2, 3], null) = "123"
    4545     * </pre>
    4546     *
    4547     * @param array
    4548     *            the array of values to join together, may be null
    4549     * @param separator
    4550     *            the separator character to use
    4551     * @return the joined String, {@code null} if null array input
    4552     * @since 3.2
    4553     */
    4554    public static String join(final long[] array, final char separator) {
    4555        if (array == null) {
    4556            return null;
    4557        }
    4558        return join(array, separator, 0, array.length);
    4559    }
    4560
    4561    /**
    4562     * <p>
    4563     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4564     * </p>
    4565     *
    4566     * <p>
    4567     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4568     * by empty strings.
    4569     * </p>
    4570     *
    4571     * <pre>
    4572     * StringUtils.join(null, *)               = null
    4573     * StringUtils.join([], *)                 = ""
    4574     * StringUtils.join([null], *)             = ""
    4575     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4576     * StringUtils.join([1, 2, 3], null) = "123"
    4577     * </pre>
    4578     *
    4579     * @param array
    4580     *            the array of values to join together, may be null
    4581     * @param delimiter
    4582     *            the separator character to use
    4583     * @param startIndex
    4584     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4585     *            array
    4586     * @param endIndex
    4587     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4588     *            the array
    4589     * @return the joined String, {@code null} if null array input
    4590     * @since 3.2
    4591     */
    4592    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
    4593        if (array == null) {
    4594            return null;
    4595        }
    4596        if (endIndex - startIndex <= 0) {
    4597            return EMPTY;
    4598        }
    4599        final StringJoiner joiner = newStringJoiner(delimiter);
    4600        for (int i = startIndex; i < endIndex; i++) {
    4601            joiner.add(String.valueOf(array[i]));
    4602        }
    4603        return joiner.toString();
    4604    }
    4605
    4606    /**
    4607     * <p>Joins the elements of the provided array into a single String
    4608     * containing the provided list of elements.</p>
    4609     *
    4610     * <p>No delimiter is added before or after the list.
    4611     * Null objects or empty strings within the array are represented by
    4612     * empty strings.</p>
    4613     *
    4614     * <pre>
    4615     * StringUtils.join(null, *)               = null
    4616     * StringUtils.join([], *)                 = ""
    4617     * StringUtils.join([null], *)             = ""
    4618     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4619     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4620     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4621     * </pre>
    4622     *
    4623     * @param array  the array of values to join together, may be null
    4624     * @param delimiter  the separator character to use
    4625     * @return the joined String, {@code null} if null array input
    4626     * @since 2.0
    4627     */
    4628    public static String join(final Object[] array, final char delimiter) {
    4629        if (array == null) {
    4630            return null;
    4631        }
    4632        return join(array, delimiter, 0, array.length);
    4633    }
    4634
    4635    /**
    4636     * <p>Joins the elements of the provided array into a single String
    4637     * containing the provided list of elements.</p>
    4638     *
    4639     * <p>No delimiter is added before or after the list.
    4640     * Null objects or empty strings within the array are represented by
    4641     * empty strings.</p>
    4642     *
    4643     * <pre>
    4644     * StringUtils.join(null, *)               = null
    4645     * StringUtils.join([], *)                 = ""
    4646     * StringUtils.join([null], *)             = ""
    4647     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4648     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4649     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4650     * </pre>
    4651     *
    4652     * @param array  the array of values to join together, may be null
    4653     * @param delimiter  the separator character to use
    4654     * @param startIndex the first index to start joining from.  It is
    4655     * an error to pass in a start index past the end of the array
    4656     * @param endIndex the index to stop joining from (exclusive). It is
    4657     * an error to pass in an end index past the end of the array
    4658     * @return the joined String, {@code null} if null array input
    4659     * @since 2.0
    4660     */
    4661    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
    4662        if (array == null) {
    4663            return null;
    4664        }
    4665        if (endIndex - startIndex <= 0) {
    4666            return EMPTY;
    4667        }
    4668        final StringJoiner joiner = newStringJoiner(delimiter);
    4669        for (int i = startIndex; i < endIndex; i++) {
    4670            joiner.add(toStringOrEmpty(array[i]));
    4671        }
    4672        return joiner.toString();
    4673    }
    4674
    4675    /**
    4676     * <p>Joins the elements of the provided array into a single String
    4677     * containing the provided list of elements.</p>
    4678     *
    4679     * <p>No delimiter is added before or after the list.
    4680     * A {@code null} separator is the same as an empty String ("").
    4681     * Null objects or empty strings within the array are represented by
    4682     * empty strings.</p>
    4683     *
    4684     * <pre>
    4685     * StringUtils.join(null, *)                = null
    4686     * StringUtils.join([], *)                  = ""
    4687     * StringUtils.join([null], *)              = ""
    4688     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    4689     * StringUtils.join(["a", "b", "c"], null)  = "abc"
    4690     * StringUtils.join(["a", "b", "c"], "")    = "abc"
    4691     * StringUtils.join([null, "", "a"], ',')   = ",,a"
    4692     * </pre>
    4693     *
    4694     * @param array  the array of values to join together, may be null
    4695     * @param delimiter  the separator character to use, null treated as ""
    4696     * @return the joined String, {@code null} if null array input
    4697     */
    4698    public static String join(final Object[] array, final String delimiter) {
    4699        if (array == null) {
    4700            return null;
    4701        }
    4702        return join(array, delimiter, 0, array.length);
    4703    }
    4704
    4705    /**
    4706     * <p>Joins the elements of the provided array into a single String
    4707     * containing the provided list of elements.</p>
    4708     *
    4709     * <p>No delimiter is added before or after the list.
    4710     * A {@code null} separator is the same as an empty String ("").
    4711     * Null objects or empty strings within the array are represented by
    4712     * empty strings.</p>
    4713     *
    4714     * <pre>
    4715     * StringUtils.join(null, *, *, *)                = null
    4716     * StringUtils.join([], *, *, *)                  = ""
    4717     * StringUtils.join([null], *, *, *)              = ""
    4718     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
    4719     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
    4720     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
    4721     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
    4722     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
    4723     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
    4724     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
    4725     * </pre>
    4726     *
    4727     * @param array  the array of values to join together, may be null
    4728     * @param delimiter  the separator character to use, null treated as ""
    4729     * @param startIndex the first index to start joining from.
    4730     * @param endIndex the index to stop joining from (exclusive).
    4731     * @return the joined String, {@code null} if null array input; or the empty string
    4732     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
    4733     * {@code endIndex - startIndex}
    4734     * @throws ArrayIndexOutOfBoundsException ife<br>
    4735     * {@code startIndex < 0} or <br>
    4736     * {@code startIndex >= array.length()} or <br>
    4737     * {@code endIndex < 0} or <br>
    4738     * {@code endIndex > array.length()}
    4739     */
    4740    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
    4741        if (array == null) {
    4742            return null;
    4743        }
    4744        if (endIndex - startIndex <= 0) {
    4745            return EMPTY;
    4746        }
    4747        final StringJoiner joiner = new StringJoiner(toStringOrEmpty(delimiter));
    4748        for (int i = startIndex; i < endIndex; i++) {
    4749            joiner.add(toStringOrEmpty(array[i]));
    4750        }
    4751        return joiner.toString();
    4752    }
    4753
    4754    /**
    4755     * <p>
    4756     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4757     * </p>
    4758     *
    4759     * <p>
    4760     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4761     * by empty strings.
    4762     * </p>
    4763     *
    4764     * <pre>
    4765     * StringUtils.join(null, *)               = null
    4766     * StringUtils.join([], *)                 = ""
    4767     * StringUtils.join([null], *)             = ""
    4768     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4769     * StringUtils.join([1, 2, 3], null) = "123"
    4770     * </pre>
    4771     *
    4772     * @param array
    4773     *            the array of values to join together, may be null
    4774     * @param delimiter
    4775     *            the separator character to use
    4776     * @return the joined String, {@code null} if null array input
    4777     * @since 3.2
    4778     */
    4779    public static String join(final short[] array, final char delimiter) {
    4780        if (array == null) {
    4781            return null;
    4782        }
    4783        return join(array, delimiter, 0, array.length);
    4784    }
    4785
    4786    /**
    4787     * <p>
    4788     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4789     * </p>
    4790     *
    4791     * <p>
    4792     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4793     * by empty strings.
    4794     * </p>
    4795     *
    4796     * <pre>
    4797     * StringUtils.join(null, *)               = null
    4798     * StringUtils.join([], *)                 = ""
    4799     * StringUtils.join([null], *)             = ""
    4800     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4801     * StringUtils.join([1, 2, 3], null) = "123"
    4802     * </pre>
    4803     *
    4804     * @param array
    4805     *            the array of values to join together, may be null
    4806     * @param delimiter
    4807     *            the separator character to use
    4808     * @param startIndex
    4809     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4810     *            array
    4811     * @param endIndex
    4812     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4813     *            the array
    4814     * @return the joined String, {@code null} if null array input
    4815     * @since 3.2
    4816     */
    4817    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
    4818        if (array == null) {
    4819            return null;
    4820        }
    4821        if (endIndex - startIndex <= 0) {
    4822            return EMPTY;
    4823        }
    4824        final StringJoiner joiner = newStringJoiner(delimiter);
    4825        for (int i = startIndex; i < endIndex; i++) {
    4826            joiner.add(String.valueOf(array[i]));
    4827        }
    4828        return joiner.toString();
    4829    }
    4830
    4831    /**
    4832     * <p>Joins the elements of the provided array into a single String
    4833     * containing the provided list of elements.</p>
    4834     *
    4835     * <p>No separator is added to the joined String.
    4836     * Null objects or empty strings within the array are represented by
    4837     * empty strings.</p>
    4838     *
    4839     * <pre>
    4840     * StringUtils.join(null)            = null
    4841     * StringUtils.join([])              = ""
    4842     * StringUtils.join([null])          = ""
    4843     * StringUtils.join(["a", "b", "c"]) = "abc"
    4844     * StringUtils.join([null, "", "a"]) = "a"
    4845     * </pre>
    4846     *
    4847     * @param <T> the specific type of values to join together
    4848     * @param elements  the values to join together, may be null
    4849     * @return the joined String, {@code null} if null array input
    4850     * @since 2.0
    4851     * @since 3.0 Changed signature to use varargs
    4852     */
    4853    @SafeVarargs
    4854    public static <T> String join(final T... elements) {
    4855        return join(elements, null);
    4856    }
    4857
    4858    /**
    4859     * <p>Joins the elements of the provided varargs into a
    4860     * single String containing the provided elements.</p>
    4861     *
    4862     * <p>No delimiter is added before or after the list.
    4863     * {@code null} elements and separator are treated as empty Strings ("").</p>
    4864     *
    4865     * <pre>
    4866     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
    4867     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
    4868     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
    4869     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
    4870     * </pre>
    4871     *
    4872     * @param delimiter the separator character to use, null treated as ""
    4873     * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
    4874     * @return the joined String.
    4875     * @throws java.lang.IllegalArgumentException if a null varargs is provided
    4876     * @since 3.5
    4877     */
    4878    public static String joinWith(final String delimiter, final Object... array) {
    4879        if (array == null) {
    4880            throw new IllegalArgumentException("Object varargs must not be null");
    4881        }
    4882        return join(array, delimiter);
    4883    }
    4884
    4885    /**
    4886     * <p>Finds the last index within a CharSequence, handling {@code null}.
    4887     * This method uses {@link String#lastIndexOf(String)} if possible.</p>
    4888     *
    4889     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    4890     *
    4891     * <pre>
    4892     * StringUtils.lastIndexOf(null, *)          = -1
    4893     * StringUtils.lastIndexOf(*, null)          = -1
    4894     * StringUtils.lastIndexOf("", "")           = 0
    4895     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    4896     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    4897     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    4898     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    4899     * </pre>
    4900     *
    4901     * @param seq  the CharSequence to check, may be null
    4902     * @param searchSeq  the CharSequence to find, may be null
    4903     * @return the last index of the search String,
    4904     *  -1 if no match or {@code null} string input
    4905     * @since 2.0
    4906     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
    4907     */
    4908    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
    4909        if (seq == null) {
    4910            return INDEX_NOT_FOUND;
    4911        }
    4912        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
    4913    }
    4914
    4915    /**
    4916     * <p>Finds the last index within a CharSequence, handling {@code null}.
    4917     * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
    4918     *
    4919     * <p>A {@code null} CharSequence will return {@code -1}.
    4920     * A negative start position returns {@code -1}.
    4921     * An empty ("") search CharSequence always matches unless the start position is negative.
    4922     * A start position greater than the string length searches the whole string.
    4923     * The search starts at the startPos and works backwards; matches starting after the start
    4924     * position are ignored.
    4925     * </p>
    4926     *
    4927     * <pre>
    4928     * StringUtils.lastIndexOf(null, *, *)          = -1
    4929     * StringUtils.lastIndexOf(*, null, *)          = -1
    4930     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    4931     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    4932     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    4933     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    4934     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    4935     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    4936     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    4937     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
    4938     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
    4939     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
    4940     * </pre>
    4941     *
    4942     * @param seq  the CharSequence to check, may be null
    4943     * @param searchSeq  the CharSequence to find, may be null
    4944     * @param startPos  the start position, negative treated as zero
    4945     * @return the last index of the search CharSequence (always &le; startPos),
    4946     *  -1 if no match or {@code null} string input
    4947     * @since 2.0
    4948     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
    4949     */
    4950    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    4951        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
    4952    }
    4953
    4954    /**
    4955     * Returns the index within {@code seq} of the last occurrence of
    4956     * the specified character. For values of {@code searchChar} in the
    4957     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
    4958     * units) returned is the largest value <i>k</i> such that:
    4959     * <blockquote><pre>
    4960     * this.charAt(<i>k</i>) == searchChar
    4961     * </pre></blockquote>
    4962     * is true. For other values of {@code searchChar}, it is the
    4963     * largest value <i>k</i> such that:
    4964     * <blockquote><pre>
    4965     * this.codePointAt(<i>k</i>) == searchChar
    4966     * </pre></blockquote>
    4967     * is true.  In either case, if no such character occurs in this
    4968     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4969     * {@code CharSequence} will return {@code -1}. The
    4970     * {@code seq} {@code CharSequence} object is searched backwards
    4971     * starting at the last character.
    4972     *
    4973     * <pre>
    4974     * StringUtils.lastIndexOf(null, *)         = -1
    4975     * StringUtils.lastIndexOf("", *)           = -1
    4976     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    4977     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    4978     * </pre>
    4979     *
    4980     * @param seq  the {@code CharSequence} to check, may be null
    4981     * @param searchChar  the character to find
    4982     * @return the last index of the search character,
    4983     *  -1 if no match or {@code null} string input
    4984     * @since 2.0
    4985     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
    4986     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@code String}
    4987     */
    4988    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
    4989        if (isEmpty(seq)) {
    4990            return INDEX_NOT_FOUND;
    4991        }
    4992        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
    4993    }
    4994
    4995    /**
    4996     * Returns the index within {@code seq} of the last occurrence of
    4997     * the specified character, searching backward starting at the
    4998     * specified index. For values of {@code searchChar} in the range
    4999     * from 0 to 0xFFFF (inclusive), the index returned is the largest
    5000     * value <i>k</i> such that:
    5001     * <blockquote><pre>
    5002     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    5003     * </pre></blockquote>
    5004     * is true. For other values of {@code searchChar}, it is the
    5005     * largest value <i>k</i> such that:
    5006     * <blockquote><pre>
    5007     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    5008     * </pre></blockquote>
    5009     * is true. In either case, if no such character occurs in {@code seq}
    5010     * at or before position {@code startPos}, then
    5011     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    5012     * {@code CharSequence} will return {@code -1}. A start position greater
    5013     * than the string length searches the whole string.
    5014     * The search starts at the {@code startPos} and works backwards;
    5015     * matches starting after the start position are ignored.
    5016     *
    5017     * <p>All indices are specified in {@code char} values
    5018     * (Unicode code units).
    5019     *
    5020     * <pre>
    5021     * StringUtils.lastIndexOf(null, *, *)          = -1
    5022     * StringUtils.lastIndexOf("", *,  *)           = -1
    5023     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    5024     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    5025     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    5026     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    5027     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    5028     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    5029     * </pre>
    5030     *
    5031     * @param seq  the CharSequence to check, may be null
    5032     * @param searchChar  the character to find
    5033     * @param startPos  the start position
    5034     * @return the last index of the search character (always &le; startPos),
    5035     *  -1 if no match or {@code null} string input
    5036     * @since 2.0
    5037     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
    5038     */
    5039    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
    5040        if (isEmpty(seq)) {
    5041            return INDEX_NOT_FOUND;
    5042        }
    5043        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
    5044    }
    5045
    5046    /**
    5047     * <p>Find the latest index of any substring in a set of potential substrings.</p>
    5048     *
    5049     * <p>A {@code null} CharSequence will return {@code -1}.
    5050     * A {@code null} search array will return {@code -1}.
    5051     * A {@code null} or zero length search array entry will be ignored,
    5052     * but a search array containing "" will return the length of {@code str}
    5053     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
    5054     *
    5055     * <pre>
    5056     * StringUtils.lastIndexOfAny(null, *)                    = -1
    5057     * StringUtils.lastIndexOfAny(*, null)                    = -1
    5058     * StringUtils.lastIndexOfAny(*, [])                      = -1
    5059     * StringUtils.lastIndexOfAny(*, [null])                  = -1
    5060     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
    5061     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
    5062     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    5063     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    5064     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
    5065     * </pre>
    5066     *
    5067     * @param str  the CharSequence to check, may be null
    5068     * @param searchStrs  the CharSequences to search for, may be null
    5069     * @return the last index of any of the CharSequences, -1 if no match
    5070     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
    5071     */
    5072    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    5073        if (str == null || searchStrs == null) {
    5074            return INDEX_NOT_FOUND;
    5075        }
    5076        int ret = INDEX_NOT_FOUND;
    5077        int tmp = 0;
    5078        for (final CharSequence search : searchStrs) {
    5079            if (search == null) {
    5080                continue;
    5081            }
    5082            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
    5083            if (tmp > ret) {
    5084                ret = tmp;
    5085            }
    5086        }
    5087        return ret;
    5088    }
    5089
    5090    /**
    5091     * <p>Case in-sensitive find of the last index within a CharSequence.</p>
    5092     *
    5093     * <p>A {@code null} CharSequence will return {@code -1}.
    5094     * A negative start position returns {@code -1}.
    5095     * An empty ("") search CharSequence always matches unless the start position is negative.
    5096     * A start position greater than the string length searches the whole string.</p>
    5097     *
    5098     * <pre>
    5099     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    5100     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    5101     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    5102     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    5103     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    5104     * </pre>
    5105     *
    5106     * @param str  the CharSequence to check, may be null
    5107     * @param searchStr  the CharSequence to find, may be null
    5108     * @return the first index of the search CharSequence,
    5109     *  -1 if no match or {@code null} string input
    5110     * @since 2.5
    5111     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
    5112     */
    5113    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    5114        if (str == null || searchStr == null) {
    5115            return INDEX_NOT_FOUND;
    5116        }
    5117        return lastIndexOfIgnoreCase(str, searchStr, str.length());
    5118    }
    5119
    5120    /**
    5121     * <p>Case in-sensitive find of the last index within a CharSequence
    5122     * from the specified position.</p>
    5123     *
    5124     * <p>A {@code null} CharSequence will return {@code -1}.
    5125     * A negative start position returns {@code -1}.
    5126     * An empty ("") search CharSequence always matches unless the start position is negative.
    5127     * A start position greater than the string length searches the whole string.
    5128     * The search starts at the startPos and works backwards; matches starting after the start
    5129     * position are ignored.
    5130     * </p>
    5131     *
    5132     * <pre>
    5133     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    5134     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    5135     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    5136     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    5137     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    5138     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    5139     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    5140     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    5141     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    5142     * </pre>
    5143     *
    5144     * @param str  the CharSequence to check, may be null
    5145     * @param searchStr  the CharSequence to find, may be null
    5146     * @param startPos  the start position
    5147     * @return the last index of the search CharSequence (always &le; startPos),
    5148     *  -1 if no match or {@code null} input
    5149     * @since 2.5
    5150     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
    5151     */
    5152    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    5153        if (str == null || searchStr == null) {
    5154            return INDEX_NOT_FOUND;
    5155        }
    5156        final int searchStrLength = searchStr.length();
    5157        final int strLength = str.length();
    5158        if (startPos > strLength - searchStrLength) {
    5159            startPos = strLength - searchStrLength;
    5160        }
    5161        if (startPos < 0) {
    5162            return INDEX_NOT_FOUND;
    5163        }
    5164        if (searchStrLength == 0) {
    5165            return startPos;
    5166        }
    5167
    5168        for (int i = startPos; i >= 0; i--) {
    5169            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) {
    5170                return i;
    5171            }
    5172        }
    5173        return INDEX_NOT_FOUND;
    5174    }
    5175
    5176    /**
    5177     * <p>Finds the n-th last index within a String, handling {@code null}.
    5178     * This method uses {@link String#lastIndexOf(String)}.</p>
    5179     *
    5180     * <p>A {@code null} String will return {@code -1}.</p>
    5181     *
    5182     * <pre>
    5183     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    5184     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    5185     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    5186     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    5187     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    5188     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    5189     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    5190     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    5191     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    5192     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    5193     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    5194     * </pre>
    5195     *
    5196     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
    5197     *
    5198     * <pre>
    5199     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    5200     * </pre>
    5201     *
    5202     * @param str  the CharSequence to check, may be null
    5203     * @param searchStr  the CharSequence to find, may be null
    5204     * @param ordinal  the n-th last {@code searchStr} to find
    5205     * @return the n-th last index of the search CharSequence,
    5206     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5207     * @since 2.5
    5208     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
    5209     */
    5210    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5211        return ordinalIndexOf(str, searchStr, ordinal, true);
    5212    }
    5213
    5214    /**
    5215     * <p>Gets the leftmost {@code len} characters of a String.</p>
    5216     *
    5217     * <p>If {@code len} characters are not available, or the
    5218     * String is {@code null}, the String will be returned without
    5219     * an exception. An empty String is returned if len is negative.</p>
    5220     *
    5221     * <pre>
    5222     * StringUtils.left(null, *)    = null
    5223     * StringUtils.left(*, -ve)     = ""
    5224     * StringUtils.left("", *)      = ""
    5225     * StringUtils.left("abc", 0)   = ""
    5226     * StringUtils.left("abc", 2)   = "ab"
    5227     * StringUtils.left("abc", 4)   = "abc"
    5228     * </pre>
    5229     *
    5230     * @param str  the String to get the leftmost characters from, may be null
    5231     * @param len  the length of the required String
    5232     * @return the leftmost characters, {@code null} if null String input
    5233     */
    5234    public static String left(final String str, final int len) {
    5235        if (str == null) {
    5236            return null;
    5237        }
    5238        if (len < 0) {
    5239            return EMPTY;
    5240        }
    5241        if (str.length() <= len) {
    5242            return str;
    5243        }
    5244        return str.substring(0, len);
    5245    }
    5246
    5247    /**
    5248     * <p>Left pad a String with spaces (' ').</p>
    5249     *
    5250     * <p>The String is padded to the size of {@code size}.</p>
    5251     *
    5252     * <pre>
    5253     * StringUtils.leftPad(null, *)   = null
    5254     * StringUtils.leftPad("", 3)     = "   "
    5255     * StringUtils.leftPad("bat", 3)  = "bat"
    5256     * StringUtils.leftPad("bat", 5)  = "  bat"
    5257     * StringUtils.leftPad("bat", 1)  = "bat"
    5258     * StringUtils.leftPad("bat", -1) = "bat"
    5259     * </pre>
    5260     *
    5261     * @param str  the String to pad out, may be null
    5262     * @param size  the size to pad to
    5263     * @return left padded String or original String if no padding is necessary,
    5264     *  {@code null} if null String input
    5265     */
    5266    public static String leftPad(final String str, final int size) {
    5267        return leftPad(str, size, ' ');
    5268    }
    5269
    5270    /**
    5271     * <p>Left pad a String with a specified character.</p>
    5272     *
    5273     * <p>Pad to a size of {@code size}.</p>
    5274     *
    5275     * <pre>
    5276     * StringUtils.leftPad(null, *, *)     = null
    5277     * StringUtils.leftPad("", 3, 'z')     = "zzz"
    5278     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    5279     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    5280     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    5281     * StringUtils.leftPad("bat", -1, 'z') = "bat"
    5282     * </pre>
    5283     *
    5284     * @param str  the String to pad out, may be null
    5285     * @param size  the size to pad to
    5286     * @param padChar  the character to pad with
    5287     * @return left padded String or original String if no padding is necessary,
    5288     *  {@code null} if null String input
    5289     * @since 2.0
    5290     */
    5291    public static String leftPad(final String str, final int size, final char padChar) {
    5292        if (str == null) {
    5293            return null;
    5294        }
    5295        final int pads = size - str.length();
    5296        if (pads <= 0) {
    5297            return str; // returns original String when possible
    5298        }
    5299        if (pads > PAD_LIMIT) {
    5300            return leftPad(str, size, String.valueOf(padChar));
    5301        }
    5302        return repeat(padChar, pads).concat(str);
    5303    }
    5304
    5305    /**
    5306     * <p>Left pad a String with a specified String.</p>
    5307     *
    5308     * <p>Pad to a size of {@code size}.</p>
    5309     *
    5310     * <pre>
    5311     * StringUtils.leftPad(null, *, *)      = null
    5312     * StringUtils.leftPad("", 3, "z")      = "zzz"
    5313     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    5314     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    5315     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    5316     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    5317     * StringUtils.leftPad("bat", -1, "yz") = "bat"
    5318     * StringUtils.leftPad("bat", 5, null)  = "  bat"
    5319     * StringUtils.leftPad("bat", 5, "")    = "  bat"
    5320     * </pre>
    5321     *
    5322     * @param str  the String to pad out, may be null
    5323     * @param size  the size to pad to
    5324     * @param padStr  the String to pad with, null or empty treated as single space
    5325     * @return left padded String or original String if no padding is necessary,
    5326     *  {@code null} if null String input
    5327     */
    5328    public static String leftPad(final String str, final int size, String padStr) {
    5329        if (str == null) {
    5330            return null;
    5331        }
    5332        if (isEmpty(padStr)) {
    5333            padStr = SPACE;
    5334        }
    5335        final int padLen = padStr.length();
    5336        final int strLen = str.length();
    5337        final int pads = size - strLen;
    5338        if (pads <= 0) {
    5339            return str; // returns original String when possible
    5340        }
    5341        if (padLen == 1 && pads <= PAD_LIMIT) {
    5342            return leftPad(str, size, padStr.charAt(0));
    5343        }
    5344
    5345        if (pads == padLen) {
    5346            return padStr.concat(str);
    5347        } else if (pads < padLen) {
    5348            return padStr.substring(0, pads).concat(str);
    5349        } else {
    5350            final char[] padding = new char[pads];
    5351            final char[] padChars = padStr.toCharArray();
    5352            for (int i = 0; i < pads; i++) {
    5353                padding[i] = padChars[i % padLen];
    5354            }
    5355            return new String(padding).concat(str);
    5356        }
    5357    }
    5358
    5359    /**
    5360     * Gets a CharSequence length or {@code 0} if the CharSequence is
    5361     * {@code null}.
    5362     *
    5363     * @param cs
    5364     *            a CharSequence or {@code null}
    5365     * @return CharSequence length or {@code 0} if the CharSequence is
    5366     *         {@code null}.
    5367     * @since 2.4
    5368     * @since 3.0 Changed signature from length(String) to length(CharSequence)
    5369     */
    5370    public static int length(final CharSequence cs) {
    5371        return cs == null ? 0 : cs.length();
    5372    }
    5373
    5374    /**
    5375     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
    5376     *
    5377     * <p>A {@code null} input String returns {@code null}.</p>
    5378     *
    5379     * <pre>
    5380     * StringUtils.lowerCase(null)  = null
    5381     * StringUtils.lowerCase("")    = ""
    5382     * StringUtils.lowerCase("aBc") = "abc"
    5383     * </pre>
    5384     *
    5385     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
    5386     * the result of this method is affected by the current locale.
    5387     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    5388     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    5389     *
    5390     * @param str  the String to lower case, may be null
    5391     * @return the lower cased String, {@code null} if null String input
    5392     */
    5393    public static String lowerCase(final String str) {
    5394        if (str == null) {
    5395            return null;
    5396        }
    5397        return str.toLowerCase();
    5398    }
    5399
    5400    /**
    5401     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
    5402     *
    5403     * <p>A {@code null} input String returns {@code null}.</p>
    5404     *
    5405     * <pre>
    5406     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    5407     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    5408     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    5409     * </pre>
    5410     *
    5411     * @param str  the String to lower case, may be null
    5412     * @param locale  the locale that defines the case transformation rules, must not be null
    5413     * @return the lower cased String, {@code null} if null String input
    5414     * @since 2.5
    5415     */
    5416    public static String lowerCase(final String str, final Locale locale) {
    5417        if (str == null) {
    5418            return null;
    5419        }
    5420        return str.toLowerCase(LocaleUtils.toLocale(locale));
    5421    }
    5422
    5423    private static int[] matches(final CharSequence first, final CharSequence second) {
    5424        final CharSequence max;
    5425        final CharSequence min;
    5426        if (first.length() > second.length()) {
    5427            max = first;
    5428            min = second;
    5429        } else {
    5430            max = second;
    5431            min = first;
    5432        }
    5433        final int range = Math.max(max.length() / 2 - 1, 0);
    5434        final int[] matchIndexes = new int[min.length()];
    5435        Arrays.fill(matchIndexes, -1);
    5436        final boolean[] matchFlags = new boolean[max.length()];
    5437        int matches = 0;
    5438        for (int mi = 0; mi < min.length(); mi++) {
    5439            final char c1 = min.charAt(mi);
    5440            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
    5441                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
    5442                    matchIndexes[mi] = xi;
    5443                    matchFlags[xi] = true;
    5444                    matches++;
    5445                    break;
    5446                }
    5447            }
    5448        }
    5449        final char[] ms1 = new char[matches];
    5450        final char[] ms2 = new char[matches];
    5451        for (int i = 0, si = 0; i < min.length(); i++) {
    5452            if (matchIndexes[i] != -1) {
    5453                ms1[si] = min.charAt(i);
    5454                si++;
    5455            }
    5456        }
    5457        for (int i = 0, si = 0; i < max.length(); i++) {
    5458            if (matchFlags[i]) {
    5459                ms2[si] = max.charAt(i);
    5460                si++;
    5461            }
    5462        }
    5463        int transpositions = 0;
    5464        for (int mi = 0; mi < ms1.length; mi++) {
    5465            if (ms1[mi] != ms2[mi]) {
    5466                transpositions++;
    5467            }
    5468        }
    5469        int prefix = 0;
    5470        for (int mi = 0; mi < min.length(); mi++) {
    5471            if (first.charAt(mi) == second.charAt(mi)) {
    5472                prefix++;
    5473            } else {
    5474                break;
    5475            }
    5476        }
    5477        return new int[] { matches, transpositions / 2, prefix, max.length() };
    5478    }
    5479
    5480    /**
    5481     * <p>Gets {@code len} characters from the middle of a String.</p>
    5482     *
    5483     * <p>If {@code len} characters are not available, the remainder
    5484     * of the String will be returned without an exception. If the
    5485     * String is {@code null}, {@code null} will be returned.
    5486     * An empty String is returned if len is negative or exceeds the
    5487     * length of {@code str}.</p>
    5488     *
    5489     * <pre>
    5490     * StringUtils.mid(null, *, *)    = null
    5491     * StringUtils.mid(*, *, -ve)     = ""
    5492     * StringUtils.mid("", 0, *)      = ""
    5493     * StringUtils.mid("abc", 0, 2)   = "ab"
    5494     * StringUtils.mid("abc", 0, 4)   = "abc"
    5495     * StringUtils.mid("abc", 2, 4)   = "c"
    5496     * StringUtils.mid("abc", 4, 2)   = ""
    5497     * StringUtils.mid("abc", -2, 2)  = "ab"
    5498     * </pre>
    5499     *
    5500     * @param str  the String to get the characters from, may be null
    5501     * @param pos  the position to start from, negative treated as zero
    5502     * @param len  the length of the required String
    5503     * @return the middle characters, {@code null} if null String input
    5504     */
    5505    public static String mid(final String str, int pos, final int len) {
    5506        if (str == null) {
    5507            return null;
    5508        }
    5509        if (len < 0 || pos > str.length()) {
    5510            return EMPTY;
    5511        }
    5512        if (pos < 0) {
    5513            pos = 0;
    5514        }
    5515        if (str.length() <= pos + len) {
    5516            return str.substring(pos);
    5517        }
    5518        return str.substring(pos, pos + len);
    5519    }
    5520
    5521    private static StringJoiner newStringJoiner(final char delimiter) {
    5522        return new StringJoiner(String.valueOf(delimiter));
    5523    }
    5524
    5525    /**
    5526     * <p>
    5527     * Similar to <a
    5528     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
    5529     * -space</a>
    5530     * </p>
    5531     * <p>
    5532     * The function returns the argument string with whitespace normalized by using
    5533     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
    5534     * and then replacing sequences of whitespace characters by a single space.
    5535     * </p>
    5536     * In XML Whitespace characters are the same as those allowed by the <a
    5537     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
    5538     * <p>
    5539     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
    5540     *
    5541     * <p>For reference:</p>
    5542     * <ul>
    5543     * <li>\x0B = vertical tab</li>
    5544     * <li>\f = #xC = form feed</li>
    5545     * <li>#x20 = space</li>
    5546     * <li>#x9 = \t</li>
    5547     * <li>#xA = \n</li>
    5548     * <li>#xD = \r</li>
    5549     * </ul>
    5550     *
    5551     * <p>
    5552     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
    5553     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
    5554     * ends of this String.
    5555     * </p>
    5556     *
    5557     * @see Pattern
    5558     * @see #trim(String)
    5559     * @see <a
    5560     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
    5561     * @param str the source String to normalize whitespaces from, may be null
    5562     * @return the modified string with whitespace normalized, {@code null} if null String input
    5563     *
    5564     * @since 3.0
    5565     */
    5566    public static String normalizeSpace(final String str) {
    5567        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
    5568        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
    5569        if (isEmpty(str)) {
    5570            return str;
    5571        }
    5572        final int size = str.length();
    5573        final char[] newChars = new char[size];
    5574        int count = 0;
    5575        int whitespacesCount = 0;
    5576        boolean startWhitespaces = true;
    5577        for (int i = 0; i < size; i++) {
    5578            final char actualChar = str.charAt(i);
    5579            final boolean isWhitespace = Character.isWhitespace(actualChar);
    5580            if (isWhitespace) {
    5581                if (whitespacesCount == 0 && !startWhitespaces) {
    5582                    newChars[count++] = SPACE.charAt(0);
    5583                }
    5584                whitespacesCount++;
    5585            } else {
    5586                startWhitespaces = false;
    5587                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
    5588                whitespacesCount = 0;
    5589            }
    5590        }
    5591        if (startWhitespaces) {
    5592            return EMPTY;
    5593        }
    5594        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
    5595    }
    5596
    5597    /**
    5598     * <p>Finds the n-th index within a CharSequence, handling {@code null}.
    5599     * This method uses {@link String#indexOf(String)} if possible.</p>
    5600     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
    5601     * incrementing the starting index by one after each successful match
    5602     * (unless {@code searchStr} is an empty string in which case the position
    5603     * is never incremented and {@code 0} is returned immediately).
    5604     * This means that matches may overlap.</p>
    5605     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5606     *
    5607     * <pre>
    5608     * StringUtils.ordinalIndexOf(null, *, *)          = -1
    5609     * StringUtils.ordinalIndexOf(*, null, *)          = -1
    5610     * StringUtils.ordinalIndexOf("", "", *)           = 0
    5611     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    5612     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    5613     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    5614     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    5615     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    5616     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    5617     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    5618     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    5619     * </pre>
    5620     *
    5621     * <p>Matches may overlap:</p>
    5622     * <pre>
    5623     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
    5624     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
    5625     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
    5626     *
    5627     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
    5628     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
    5629     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
    5630     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
    5631     * </pre>
    5632     *
    5633     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
    5634     *
    5635     * <pre>
    5636     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    5637     * </pre>
    5638     *
    5639     * @param str  the CharSequence to check, may be null
    5640     * @param searchStr  the CharSequence to find, may be null
    5641     * @param ordinal  the n-th {@code searchStr} to find
    5642     * @return the n-th index of the search CharSequence,
    5643     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5644     * @since 2.1
    5645     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
    5646     */
    5647    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5648        return ordinalIndexOf(str, searchStr, ordinal, false);
    5649    }
    5650
    5651    /**
    5652     * <p>Finds the n-th index within a String, handling {@code null}.
    5653     * This method uses {@link String#indexOf(String)} if possible.</p>
    5654     * <p>Note that matches may overlap<p>
    5655     *
    5656     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5657     *
    5658     * @param str  the CharSequence to check, may be null
    5659     * @param searchStr  the CharSequence to find, may be null
    5660     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
    5661     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
    5662     * @return the n-th index of the search CharSequence,
    5663     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5664     */
    5665    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
    5666    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
    5667        if (str == null || searchStr == null || ordinal <= 0) {
    5668            return INDEX_NOT_FOUND;
    5669        }
    5670        if (searchStr.length() == 0) {
    5671            return lastIndex ? str.length() : 0;
    5672        }
    5673        int found = 0;
    5674        // set the initial index beyond the end of the string
    5675        // this is to allow for the initial index decrement/increment
    5676        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    5677        do {
    5678            if (lastIndex) {
    5679                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
    5680            } else {
    5681                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
    5682            }
    5683            if (index < 0) {
    5684                return index;
    5685            }
    5686            found++;
    5687        } while (found < ordinal);
    5688        return index;
    5689    }
    5690
    5691    /**
    5692     * <p>Overlays part of a String with another String.</p>
    5693     *
    5694     * <p>A {@code null} string input returns {@code null}.
    5695     * A negative index is treated as zero.
    5696     * An index greater than the string length is treated as the string length.
    5697     * The start index is always the smaller of the two indices.</p>
    5698     *
    5699     * <pre>
    5700     * StringUtils.overlay(null, *, *, *)            = null
    5701     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    5702     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    5703     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    5704     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    5705     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    5706     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    5707     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    5708     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    5709     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    5710     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    5711     * </pre>
    5712     *
    5713     * @param str  the String to do overlaying in, may be null
    5714     * @param overlay  the String to overlay, may be null
    5715     * @param start  the position to start overlaying at
    5716     * @param end  the position to stop overlaying before
    5717     * @return overlayed String, {@code null} if null String input
    5718     * @since 2.0
    5719     */
    5720    public static String overlay(final String str, String overlay, int start, int end) {
    5721        if (str == null) {
    5722            return null;
    5723        }
    5724        if (overlay == null) {
    5725            overlay = EMPTY;
    5726        }
    5727        final int len = str.length();
    5728        if (start < 0) {
    5729            start = 0;
    5730        }
    5731        if (start > len) {
    5732            start = len;
    5733        }
    5734        if (end < 0) {
    5735            end = 0;
    5736        }
    5737        if (end > len) {
    5738            end = len;
    5739        }
    5740        if (start > end) {
    5741            final int temp = start;
    5742            start = end;
    5743            end = temp;
    5744        }
    5745        return str.substring(0, start) +
    5746            overlay +
    5747            str.substring(end);
    5748    }
    5749
    5750    /**
    5751     * Prepends the prefix to the start of the string if the string does not
    5752     * already start with any of the prefixes.
    5753     *
    5754     * @param str The string.
    5755     * @param prefix The prefix to prepend to the start of the string.
    5756     * @param ignoreCase Indicates whether the compare should ignore case.
    5757     * @param prefixes Additional prefixes that are valid (optional).
    5758     *
    5759     * @return A new String if prefix was prepended, the same string otherwise.
    5760     */
    5761    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
    5762        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
    5763            return str;
    5764        }
    5765        if (ArrayUtils.isNotEmpty(prefixes)) {
    5766            for (final CharSequence p : prefixes) {
    5767                if (startsWith(str, p, ignoreCase)) {
    5768                    return str;
    5769                }
    5770            }
    5771        }
    5772        return prefix.toString() + str;
    5773    }
    5774
    5775    /**
    5776     * Prepends the prefix to the start of the string if the string does not
    5777     * already start with any of the prefixes.
    5778     *
    5779     * <pre>
    5780     * StringUtils.prependIfMissing(null, null) = null
    5781     * StringUtils.prependIfMissing("abc", null) = "abc"
    5782     * StringUtils.prependIfMissing("", "xyz") = "xyz"
    5783     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
    5784     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
    5785     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
    5786     * </pre>
    5787     * <p>With additional prefixes,</p>
    5788     * <pre>
    5789     * StringUtils.prependIfMissing(null, null, null) = null
    5790     * StringUtils.prependIfMissing("abc", null, null) = "abc"
    5791     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
    5792     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5793     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
    5794     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
    5795     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
    5796     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
    5797     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
    5798     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
    5799     * </pre>
    5800     *
    5801     * @param str The string.
    5802     * @param prefix The prefix to prepend to the start of the string.
    5803     * @param prefixes Additional prefixes that are valid.
    5804     *
    5805     * @return A new String if prefix was prepended, the same string otherwise.
    5806     *
    5807     * @since 3.2
    5808     */
    5809    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5810        return prependIfMissing(str, prefix, false, prefixes);
    5811    }
    5812
    5813    /**
    5814     * Prepends the prefix to the start of the string if the string does not
    5815     * already start, case insensitive, with any of the prefixes.
    5816     *
    5817     * <pre>
    5818     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
    5819     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
    5820     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
    5821     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
    5822     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
    5823     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
    5824     * </pre>
    5825     * <p>With additional prefixes,</p>
    5826     * <pre>
    5827     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
    5828     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
    5829     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
    5830     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5831     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    5832     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
    5833     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
    5834     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
    5835     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
    5836     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
    5837     * </pre>
    5838     *
    5839     * @param str The string.
    5840     * @param prefix The prefix to prepend to the start of the string.
    5841     * @param prefixes Additional prefixes that are valid (optional).
    5842     *
    5843     * @return A new String if prefix was prepended, the same string otherwise.
    5844     *
    5845     * @since 3.2
    5846     */
    5847    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5848        return prependIfMissing(str, prefix, true, prefixes);
    5849    }
    5850
    5851    /**
    5852     * <p>Removes all occurrences of a character from within the source string.</p>
    5853     *
    5854     * <p>A {@code null} source string will return {@code null}.
    5855     * An empty ("") source string will return the empty string.</p>
    5856     *
    5857     * <pre>
    5858     * StringUtils.remove(null, *)       = null
    5859     * StringUtils.remove("", *)         = ""
    5860     * StringUtils.remove("queued", 'u') = "qeed"
    5861     * StringUtils.remove("queued", 'z') = "queued"
    5862     * </pre>
    5863     *
    5864     * @param str  the source String to search, may be null
    5865     * @param remove  the char to search for and remove, may be null
    5866     * @return the substring with the char removed if found,
    5867     *  {@code null} if null String input
    5868     * @since 2.1
    5869     */
    5870    public static String remove(final String str, final char remove) {
    5871        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    5872            return str;
    5873        }
    5874        final char[] chars = str.toCharArray();
    5875        int pos = 0;
    5876        for (int i = 0; i < chars.length; i++) {
    5877            if (chars[i] != remove) {
    5878                chars[pos++] = chars[i];
    5879            }
    5880        }
    5881        return new String(chars, 0, pos);
    5882    }
    5883
    5884    /**
    5885     * <p>Removes all occurrences of a substring from within the source string.</p>
    5886     *
    5887     * <p>A {@code null} source string will return {@code null}.
    5888     * An empty ("") source string will return the empty string.
    5889     * A {@code null} remove string will return the source string.
    5890     * An empty ("") remove string will return the source string.</p>
    5891     *
    5892     * <pre>
    5893     * StringUtils.remove(null, *)        = null
    5894     * StringUtils.remove("", *)          = ""
    5895     * StringUtils.remove(*, null)        = *
    5896     * StringUtils.remove(*, "")          = *
    5897     * StringUtils.remove("queued", "ue") = "qd"
    5898     * StringUtils.remove("queued", "zz") = "queued"
    5899     * </pre>
    5900     *
    5901     * @param str  the source String to search, may be null
    5902     * @param remove  the String to search for and remove, may be null
    5903     * @return the substring with the string removed if found,
    5904     *  {@code null} if null String input
    5905     * @since 2.1
    5906     */
    5907    public static String remove(final String str, final String remove) {
    5908        if (isEmpty(str) || isEmpty(remove)) {
    5909            return str;
    5910        }
    5911        return replace(str, remove, EMPTY, -1);
    5912    }
    5913
    5914    /**
    5915     * <p>Removes each substring of the text String that matches the given regular expression.</p>
    5916     *
    5917     * This method is a {@code null} safe equivalent to:
    5918     * <ul>
    5919     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
    5920     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
    5921     * </ul>
    5922     *
    5923     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5924     *
    5925     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
    5926     * is NOT automatically added.
    5927     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    5928     * DOTALL is also known as single-line mode in Perl.</p>
    5929     *
    5930     * <pre>
    5931     * StringUtils.removeAll(null, *)      = null
    5932     * StringUtils.removeAll("any", (String) null)  = "any"
    5933     * StringUtils.removeAll("any", "")    = "any"
    5934     * StringUtils.removeAll("any", ".*")  = ""
    5935     * StringUtils.removeAll("any", ".+")  = ""
    5936     * StringUtils.removeAll("abc", ".?")  = ""
    5937     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
    5938     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    5939     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
    5940     * </pre>
    5941     *
    5942     * @param text  text to remove from, may be null
    5943     * @param regex  the regular expression to which this string is to be matched
    5944     * @return  the text with any removes processed,
    5945     *              {@code null} if null String input
    5946     *
    5947     * @throws  java.util.regex.PatternSyntaxException
    5948     *              if the regular expression's syntax is invalid
    5949     *
    5950     * @see #replaceAll(String, String, String)
    5951     * @see #removePattern(String, String)
    5952     * @see String#replaceAll(String, String)
    5953     * @see java.util.regex.Pattern
    5954     * @see java.util.regex.Pattern#DOTALL
    5955     * @since 3.5
    5956     *
    5957     * @deprecated Moved to RegExUtils.
    5958     */
    5959    @Deprecated
    5960    public static String removeAll(final String text, final String regex) {
    5961        return RegExUtils.removeAll(text, regex);
    5962    }
    5963
    5964    /**
    5965     * <p>Removes a substring only if it is at the end of a source string,
    5966     * otherwise returns the source string.</p>
    5967     *
    5968     * <p>A {@code null} source string will return {@code null}.
    5969     * An empty ("") source string will return the empty string.
    5970     * A {@code null} search string will return the source string.</p>
    5971     *
    5972     * <pre>
    5973     * StringUtils.removeEnd(null, *)      = null
    5974     * StringUtils.removeEnd("", *)        = ""
    5975     * StringUtils.removeEnd(*, null)      = *
    5976     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    5977     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    5978     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    5979     * StringUtils.removeEnd("abc", "")    = "abc"
    5980     * </pre>
    5981     *
    5982     * @param str  the source String to search, may be null
    5983     * @param remove  the String to search for and remove, may be null
    5984     * @return the substring with the string removed if found,
    5985     *  {@code null} if null String input
    5986     * @since 2.1
    5987     */
    5988    public static String removeEnd(final String str, final String remove) {
    5989        if (isEmpty(str) || isEmpty(remove)) {
    5990            return str;
    5991        }
    5992        if (str.endsWith(remove)) {
    5993            return str.substring(0, str.length() - remove.length());
    5994        }
    5995        return str;
    5996    }
    5997
    5998    /**
    5999     * <p>Case insensitive removal of a substring if it is at the end of a source string,
    6000     * otherwise returns the source string.</p>
    6001     *
    6002     * <p>A {@code null} source string will return {@code null}.
    6003     * An empty ("") source string will return the empty string.
    6004     * A {@code null} search string will return the source string.</p>
    6005     *
    6006     * <pre>
    6007     * StringUtils.removeEndIgnoreCase(null, *)      = null
    6008     * StringUtils.removeEndIgnoreCase("", *)        = ""
    6009     * StringUtils.removeEndIgnoreCase(*, null)      = *
    6010     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    6011     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    6012     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    6013     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    6014     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    6015     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    6016     * </pre>
    6017     *
    6018     * @param str  the source String to search, may be null
    6019     * @param remove  the String to search for (case insensitive) and remove, may be null
    6020     * @return the substring with the string removed if found,
    6021     *  {@code null} if null String input
    6022     * @since 2.4
    6023     */
    6024    public static String removeEndIgnoreCase(final String str, final String remove) {
    6025        if (isEmpty(str) || isEmpty(remove)) {
    6026            return str;
    6027        }
    6028        if (endsWithIgnoreCase(str, remove)) {
    6029            return str.substring(0, str.length() - remove.length());
    6030        }
    6031        return str;
    6032    }
    6033
    6034    /**
    6035     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
    6036     *
    6037     * This method is a {@code null} safe equivalent to:
    6038     * <ul>
    6039     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
    6040     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
    6041     * </ul>
    6042     *
    6043     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6044     *
    6045     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    6046     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6047     * DOTALL is also known as single-line mode in Perl.</p>
    6048     *
    6049     * <pre>
    6050     * StringUtils.removeFirst(null, *)      = null
    6051     * StringUtils.removeFirst("any", (String) null)  = "any"
    6052     * StringUtils.removeFirst("any", "")    = "any"
    6053     * StringUtils.removeFirst("any", ".*")  = ""
    6054     * StringUtils.removeFirst("any", ".+")  = ""
    6055     * StringUtils.removeFirst("abc", ".?")  = "bc"
    6056     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
    6057     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    6058     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
    6059     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
    6060     * </pre>
    6061     *
    6062     * @param text  text to remove from, may be null
    6063     * @param regex  the regular expression to which this string is to be matched
    6064     * @return  the text with the first replacement processed,
    6065     *              {@code null} if null String input
    6066     *
    6067     * @throws  java.util.regex.PatternSyntaxException
    6068     *              if the regular expression's syntax is invalid
    6069     *
    6070     * @see #replaceFirst(String, String, String)
    6071     * @see String#replaceFirst(String, String)
    6072     * @see java.util.regex.Pattern
    6073     * @see java.util.regex.Pattern#DOTALL
    6074     * @since 3.5
    6075     *
    6076     * @deprecated Moved to RegExUtils.
    6077     */
    6078    @Deprecated
    6079    public static String removeFirst(final String text, final String regex) {
    6080        return replaceFirst(text, regex, EMPTY);
    6081    }
    6082
    6083    /**
    6084     * <p>
    6085     * Case insensitive removal of all occurrences of a substring from within
    6086     * the source string.
    6087     * </p>
    6088     *
    6089     * <p>
    6090     * A {@code null} source string will return {@code null}. An empty ("")
    6091     * source string will return the empty string. A {@code null} remove string
    6092     * will return the source string. An empty ("") remove string will return
    6093     * the source string.
    6094     * </p>
    6095     *
    6096     * <pre>
    6097     * StringUtils.removeIgnoreCase(null, *)        = null
    6098     * StringUtils.removeIgnoreCase("", *)          = ""
    6099     * StringUtils.removeIgnoreCase(*, null)        = *
    6100     * StringUtils.removeIgnoreCase(*, "")          = *
    6101     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
    6102     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
    6103     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
    6104     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
    6105     * </pre>
    6106     *
    6107     * @param str
    6108     *            the source String to search, may be null
    6109     * @param remove
    6110     *            the String to search for (case insensitive) and remove, may be
    6111     *            null
    6112     * @return the substring with the string removed if found, {@code null} if
    6113     *         null String input
    6114     * @since 3.5
    6115     */
    6116    public static String removeIgnoreCase(final String str, final String remove) {
    6117        return replaceIgnoreCase(str, remove, EMPTY, -1);
    6118    }
    6119
    6120    /**
    6121     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
    6122     * </p>
    6123     *
    6124     * This call is a {@code null} safe equivalent to:
    6125     * <ul>
    6126     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
    6127     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
    6128     * </ul>
    6129     *
    6130     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6131     *
    6132     * <pre>
    6133     * StringUtils.removePattern(null, *)       = null
    6134     * StringUtils.removePattern("any", (String) null)   = "any"
    6135     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
    6136     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
    6137     * </pre>
    6138     *
    6139     * @param source
    6140     *            the source string
    6141     * @param regex
    6142     *            the regular expression to which this string is to be matched
    6143     * @return The resulting {@code String}
    6144     * @see #replacePattern(String, String, String)
    6145     * @see String#replaceAll(String, String)
    6146     * @see Pattern#DOTALL
    6147     * @since 3.2
    6148     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    6149     *
    6150     * @deprecated Moved to RegExUtils.
    6151     */
    6152    @Deprecated
    6153    public static String removePattern(final String source, final String regex) {
    6154        return RegExUtils.removePattern(source, regex);
    6155    }
    6156
    6157    /**
    6158     * <p>Removes a substring only if it is at the beginning of a source string,
    6159     * otherwise returns the source string.</p>
    6160     *
    6161     * <p>A {@code null} source string will return {@code null}.
    6162     * An empty ("") source string will return the empty string.
    6163     * A {@code null} search string will return the source string.</p>
    6164     *
    6165     * <pre>
    6166     * StringUtils.removeStart(null, *)      = null
    6167     * StringUtils.removeStart("", *)        = ""
    6168     * StringUtils.removeStart(*, null)      = *
    6169     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    6170     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    6171     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    6172     * StringUtils.removeStart("abc", "")    = "abc"
    6173     * </pre>
    6174     *
    6175     * @param str  the source String to search, may be null
    6176     * @param remove  the String to search for and remove, may be null
    6177     * @return the substring with the string removed if found,
    6178     *  {@code null} if null String input
    6179     * @since 2.1
    6180     */
    6181    public static String removeStart(final String str, final String remove) {
    6182        if (isEmpty(str) || isEmpty(remove)) {
    6183            return str;
    6184        }
    6185        if (str.startsWith(remove)) {
    6186            return str.substring(remove.length());
    6187        }
    6188        return str;
    6189    }
    6190
    6191    /**
    6192     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
    6193     * otherwise returns the source string.</p>
    6194     *
    6195     * <p>A {@code null} source string will return {@code null}.
    6196     * An empty ("") source string will return the empty string.
    6197     * A {@code null} search string will return the source string.</p>
    6198     *
    6199     * <pre>
    6200     * StringUtils.removeStartIgnoreCase(null, *)      = null
    6201     * StringUtils.removeStartIgnoreCase("", *)        = ""
    6202     * StringUtils.removeStartIgnoreCase(*, null)      = *
    6203     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
    6204     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
    6205     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
    6206     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    6207     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
    6208     * </pre>
    6209     *
    6210     * @param str  the source String to search, may be null
    6211     * @param remove  the String to search for (case insensitive) and remove, may be null
    6212     * @return the substring with the string removed if found,
    6213     *  {@code null} if null String input
    6214     * @since 2.4
    6215     */
    6216    public static String removeStartIgnoreCase(final String str, final String remove) {
    6217        if (str != null && startsWithIgnoreCase(str, remove)) {
    6218            return str.substring(length(remove));
    6219        }
    6220        return str;
    6221    }
    6222
    6223    /**
    6224     * <p>Returns padding using the specified delimiter repeated
    6225     * to a given length.</p>
    6226     *
    6227     * <pre>
    6228     * StringUtils.repeat('e', 0)  = ""
    6229     * StringUtils.repeat('e', 3)  = "eee"
    6230     * StringUtils.repeat('e', -2) = ""
    6231     * </pre>
    6232     *
    6233     * <p>Note: this method does not support padding with
    6234     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    6235     * as they require a pair of {@code char}s to be represented.
    6236     * If you are needing to support full I18N of your applications
    6237     * consider using {@link #repeat(String, int)} instead.
    6238     * </p>
    6239     *
    6240     * @param ch  character to repeat
    6241     * @param repeat  number of times to repeat char, negative treated as zero
    6242     * @return String with repeated character
    6243     * @see #repeat(String, int)
    6244     */
    6245    public static String repeat(final char ch, final int repeat) {
    6246        if (repeat <= 0) {
    6247            return EMPTY;
    6248        }
    6249        final char[] buf = new char[repeat];
    6250        Arrays.fill(buf, ch);
    6251        return new String(buf);
    6252    }
    6253
    6254    /**
    6255     * <p>Repeat a String {@code repeat} times to form a
    6256     * new String.</p>
    6257     *
    6258     * <pre>
    6259     * StringUtils.repeat(null, 2) = null
    6260     * StringUtils.repeat("", 0)   = ""
    6261     * StringUtils.repeat("", 2)   = ""
    6262     * StringUtils.repeat("a", 3)  = "aaa"
    6263     * StringUtils.repeat("ab", 2) = "abab"
    6264     * StringUtils.repeat("a", -2) = ""
    6265     * </pre>
    6266     *
    6267     * @param str  the String to repeat, may be null
    6268     * @param repeat  number of times to repeat str, negative treated as zero
    6269     * @return a new String consisting of the original String repeated,
    6270     *  {@code null} if null String input
    6271     */
    6272    public static String repeat(final String str, final int repeat) {
    6273        // Performance tuned for 2.0 (JDK1.4)
    6274        if (str == null) {
    6275            return null;
    6276        }
    6277        if (repeat <= 0) {
    6278            return EMPTY;
    6279        }
    6280        final int inputLength = str.length();
    6281        if (repeat == 1 || inputLength == 0) {
    6282            return str;
    6283        }
    6284        if (inputLength == 1 && repeat <= PAD_LIMIT) {
    6285            return repeat(str.charAt(0), repeat);
    6286        }
    6287
    6288        final int outputLength = inputLength * repeat;
    6289        switch (inputLength) {
    6290            case 1 :
    6291                return repeat(str.charAt(0), repeat);
    6292            case 2 :
    6293                final char ch0 = str.charAt(0);
    6294                final char ch1 = str.charAt(1);
    6295                final char[] output2 = new char[outputLength];
    6296                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
    6297                    output2[i] = ch0;
    6298                    output2[i + 1] = ch1;
    6299                }
    6300                return new String(output2);
    6301            default :
    6302                final StringBuilder buf = new StringBuilder(outputLength);
    6303                for (int i = 0; i < repeat; i++) {
    6304                    buf.append(str);
    6305                }
    6306                return buf.toString();
    6307        }
    6308    }
    6309
    6310    /**
    6311     * <p>Repeat a String {@code repeat} times to form a
    6312     * new String, with a String separator injected each time. </p>
    6313     *
    6314     * <pre>
    6315     * StringUtils.repeat(null, null, 2) = null
    6316     * StringUtils.repeat(null, "x", 2)  = null
    6317     * StringUtils.repeat("", null, 0)   = ""
    6318     * StringUtils.repeat("", "", 2)     = ""
    6319     * StringUtils.repeat("", "x", 3)    = "xxx"
    6320     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    6321     * </pre>
    6322     *
    6323     * @param str        the String to repeat, may be null
    6324     * @param separator  the String to inject, may be null
    6325     * @param repeat     number of times to repeat str, negative treated as zero
    6326     * @return a new String consisting of the original String repeated,
    6327     *  {@code null} if null String input
    6328     * @since 2.5
    6329     */
    6330    public static String repeat(final String str, final String separator, final int repeat) {
    6331        if (str == null || separator == null) {
    6332            return repeat(str, repeat);
    6333        }
    6334        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    6335        final String result = repeat(str + separator, repeat);
    6336        return removeEnd(result, separator);
    6337    }
    6338
    6339    /**
    6340     * <p>Replaces all occurrences of a String within another String.</p>
    6341     *
    6342     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6343     *
    6344     * <pre>
    6345     * StringUtils.replace(null, *, *)        = null
    6346     * StringUtils.replace("", *, *)          = ""
    6347     * StringUtils.replace("any", null, *)    = "any"
    6348     * StringUtils.replace("any", *, null)    = "any"
    6349     * StringUtils.replace("any", "", *)      = "any"
    6350     * StringUtils.replace("aba", "a", null)  = "aba"
    6351     * StringUtils.replace("aba", "a", "")    = "b"
    6352     * StringUtils.replace("aba", "a", "z")   = "zbz"
    6353     * </pre>
    6354     *
    6355     * @see #replace(String text, String searchString, String replacement, int max)
    6356     * @param text  text to search and replace in, may be null
    6357     * @param searchString  the String to search for, may be null
    6358     * @param replacement  the String to replace it with, may be null
    6359     * @return the text with any replacements processed,
    6360     *  {@code null} if null String input
    6361     */
    6362    public static String replace(final String text, final String searchString, final String replacement) {
    6363        return replace(text, searchString, replacement, -1);
    6364    }
    6365
    6366    /**
    6367     * <p>Replaces a String with another String inside a larger String,
    6368     * for the first {@code max} values of the search String.</p>
    6369     *
    6370     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6371     *
    6372     * <pre>
    6373     * StringUtils.replace(null, *, *, *)         = null
    6374     * StringUtils.replace("", *, *, *)           = ""
    6375     * StringUtils.replace("any", null, *, *)     = "any"
    6376     * StringUtils.replace("any", *, null, *)     = "any"
    6377     * StringUtils.replace("any", "", *, *)       = "any"
    6378     * StringUtils.replace("any", *, *, 0)        = "any"
    6379     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    6380     * StringUtils.replace("abaa", "a", "", -1)   = "b"
    6381     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    6382     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    6383     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    6384     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    6385     * </pre>
    6386     *
    6387     * @param text  text to search and replace in, may be null
    6388     * @param searchString  the String to search for, may be null
    6389     * @param replacement  the String to replace it with, may be null
    6390     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6391     * @return the text with any replacements processed,
    6392     *  {@code null} if null String input
    6393     */
    6394    public static String replace(final String text, final String searchString, final String replacement, final int max) {
    6395        return replace(text, searchString, replacement, max, false);
    6396    }
    6397
    6398    /**
    6399     * <p>Replaces a String with another String inside a larger String,
    6400     * for the first {@code max} values of the search String,
    6401     * case sensitively/insensitively based on {@code ignoreCase} value.</p>
    6402     *
    6403     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6404     *
    6405     * <pre>
    6406     * StringUtils.replace(null, *, *, *, false)         = null
    6407     * StringUtils.replace("", *, *, *, false)           = ""
    6408     * StringUtils.replace("any", null, *, *, false)     = "any"
    6409     * StringUtils.replace("any", *, null, *, false)     = "any"
    6410     * StringUtils.replace("any", "", *, *, false)       = "any"
    6411     * StringUtils.replace("any", *, *, 0, false)        = "any"
    6412     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
    6413     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
    6414     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
    6415     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
    6416     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
    6417     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
    6418     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
    6419     * </pre>
    6420     *
    6421     * @param text  text to search and replace in, may be null
    6422     * @param searchString  the String to search for (case insensitive), may be null
    6423     * @param replacement  the String to replace it with, may be null
    6424     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6425     * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
    6426     * @return the text with any replacements processed,
    6427     *  {@code null} if null String input
    6428     */
    6429     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
    6430         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
    6431             return text;
    6432         }
    6433         if (ignoreCase) {
    6434             searchString = searchString.toLowerCase();
    6435         }
    6436         int start = 0;
    6437         int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
    6438         if (end == INDEX_NOT_FOUND) {
    6439             return text;
    6440         }
    6441         final int replLength = searchString.length();
    6442         int increase = Math.max(replacement.length() - replLength, 0);
    6443         increase *= max < 0 ? 16 : Math.min(max, 64);
    6444         final StringBuilder buf = new StringBuilder(text.length() + increase);
    6445         while (end != INDEX_NOT_FOUND) {
    6446             buf.append(text, start, end).append(replacement);
    6447             start = end + replLength;
    6448             if (--max == 0) {
    6449                 break;
    6450             }
    6451             end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
    6452         }
    6453         buf.append(text, start, text.length());
    6454         return buf.toString();
    6455     }
    6456
    6457    /**
    6458     * <p>Replaces each substring of the text String that matches the given regular expression
    6459     * with the given replacement.</p>
    6460     *
    6461     * This method is a {@code null} safe equivalent to:
    6462     * <ul>
    6463     *  <li>{@code text.replaceAll(regex, replacement)}</li>
    6464     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
    6465     * </ul>
    6466     *
    6467     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6468     *
    6469     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
    6470     * is NOT automatically added.
    6471     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6472     * DOTALL is also known as single-line mode in Perl.</p>
    6473     *
    6474     * <pre>
    6475     * StringUtils.replaceAll(null, *, *)       = null
    6476     * StringUtils.replaceAll("any", (String) null, *)   = "any"
    6477     * StringUtils.replaceAll("any", *, null)   = "any"
    6478     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
    6479     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
    6480     * StringUtils.replaceAll("", ".+", "zzz")  = ""
    6481     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
    6482     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
    6483     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    6484     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
    6485     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    6486     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    6487     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6488     * </pre>
    6489     *
    6490     * @param text  text to search and replace in, may be null
    6491     * @param regex  the regular expression to which this string is to be matched
    6492     * @param replacement  the string to be substituted for each match
    6493     * @return  the text with any replacements processed,
    6494     *              {@code null} if null String input
    6495     *
    6496     * @throws  java.util.regex.PatternSyntaxException
    6497     *              if the regular expression's syntax is invalid
    6498     *
    6499     * @see #replacePattern(String, String, String)
    6500     * @see String#replaceAll(String, String)
    6501     * @see java.util.regex.Pattern
    6502     * @see java.util.regex.Pattern#DOTALL
    6503     * @since 3.5
    6504     *
    6505     * @deprecated Moved to RegExUtils.
    6506     */
    6507    @Deprecated
    6508    public static String replaceAll(final String text, final String regex, final String replacement) {
    6509        return RegExUtils.replaceAll(text, regex, replacement);
    6510    }
    6511
    6512    /**
    6513     * <p>Replaces all occurrences of a character in a String with another.
    6514     * This is a null-safe version of {@link String#replace(char, char)}.</p>
    6515     *
    6516     * <p>A {@code null} string input returns {@code null}.
    6517     * An empty ("") string input returns an empty string.</p>
    6518     *
    6519     * <pre>
    6520     * StringUtils.replaceChars(null, *, *)        = null
    6521     * StringUtils.replaceChars("", *, *)          = ""
    6522     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    6523     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    6524     * </pre>
    6525     *
    6526     * @param str  String to replace characters in, may be null
    6527     * @param searchChar  the character to search for, may be null
    6528     * @param replaceChar  the character to replace, may be null
    6529     * @return modified String, {@code null} if null string input
    6530     * @since 2.0
    6531     */
    6532    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
    6533        if (str == null) {
    6534            return null;
    6535        }
    6536        return str.replace(searchChar, replaceChar);
    6537    }
    6538
    6539    /**
    6540     * <p>Replaces multiple characters in a String in one go.
    6541     * This method can also be used to delete characters.</p>
    6542     *
    6543     * <p>For example:<br>
    6544     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
    6545     *
    6546     * <p>A {@code null} string input returns {@code null}.
    6547     * An empty ("") string input returns an empty string.
    6548     * A null or empty set of search characters returns the input string.</p>
    6549     *
    6550     * <p>The length of the search characters should normally equal the length
    6551     * of the replace characters.
    6552     * If the search characters is longer, then the extra search characters
    6553     * are deleted.
    6554     * If the search characters is shorter, then the extra replace characters
    6555     * are ignored.</p>
    6556     *
    6557     * <pre>
    6558     * StringUtils.replaceChars(null, *, *)           = null
    6559     * StringUtils.replaceChars("", *, *)             = ""
    6560     * StringUtils.replaceChars("abc", null, *)       = "abc"
    6561     * StringUtils.replaceChars("abc", "", *)         = "abc"
    6562     * StringUtils.replaceChars("abc", "b", null)     = "ac"
    6563     * StringUtils.replaceChars("abc", "b", "")       = "ac"
    6564     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    6565     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    6566     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    6567     * </pre>
    6568     *
    6569     * @param str  String to replace characters in, may be null
    6570     * @param searchChars  a set of characters to search for, may be null
    6571     * @param replaceChars  a set of characters to replace, may be null
    6572     * @return modified String, {@code null} if null string input
    6573     * @since 2.0
    6574     */
    6575    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
    6576        if (isEmpty(str) || isEmpty(searchChars)) {
    6577            return str;
    6578        }
    6579        if (replaceChars == null) {
    6580            replaceChars = EMPTY;
    6581        }
    6582        boolean modified = false;
    6583        final int replaceCharsLength = replaceChars.length();
    6584        final int strLength = str.length();
    6585        final StringBuilder buf = new StringBuilder(strLength);
    6586        for (int i = 0; i < strLength; i++) {
    6587            final char ch = str.charAt(i);
    6588            final int index = searchChars.indexOf(ch);
    6589            if (index >= 0) {
    6590                modified = true;
    6591                if (index < replaceCharsLength) {
    6592                    buf.append(replaceChars.charAt(index));
    6593                }
    6594            } else {
    6595                buf.append(ch);
    6596            }
    6597        }
    6598        if (modified) {
    6599            return buf.toString();
    6600        }
    6601        return str;
    6602    }
    6603
    6604    /**
    6605     * <p>
    6606     * Replaces all occurrences of Strings within another String.
    6607     * </p>
    6608     *
    6609     * <p>
    6610     * A {@code null} reference passed to this method is a no-op, or if
    6611     * any "search string" or "string to replace" is null, that replace will be
    6612     * ignored. This will not repeat. For repeating replaces, call the
    6613     * overloaded method.
    6614     * </p>
    6615     *
    6616     * <pre>
    6617     *  StringUtils.replaceEach(null, *, *)        = null
    6618     *  StringUtils.replaceEach("", *, *)          = ""
    6619     *  StringUtils.replaceEach("aba", null, null) = "aba"
    6620     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
    6621     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
    6622     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
    6623     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
    6624     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
    6625     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    6626     *  (example of how it does not repeat)
    6627     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    6628     * </pre>
    6629     *
    6630     * @param text
    6631     *            text to search and replace in, no-op if null
    6632     * @param searchList
    6633     *            the Strings to search for, no-op if null
    6634     * @param replacementList
    6635     *            the Strings to replace them with, no-op if null
    6636     * @return the text with any replacements processed, {@code null} if
    6637     *         null String input
    6638     * @throws IllegalArgumentException
    6639     *             if the lengths of the arrays are not the same (null is ok,
    6640     *             and/or size 0)
    6641     * @since 2.4
    6642     */
    6643    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
    6644        return replaceEach(text, searchList, replacementList, false, 0);
    6645    }
    6646
    6647    /**
    6648     * <p>
    6649     * Replace all occurrences of Strings within another String.
    6650     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
    6651     * {@link #replaceEach(String, String[], String[])}
    6652     * </p>
    6653     *
    6654     * <p>
    6655     * A {@code null} reference passed to this method is a no-op, or if
    6656     * any "search string" or "string to replace" is null, that replace will be
    6657     * ignored.
    6658     * </p>
    6659     *
    6660     * <pre>
    6661     *  StringUtils.replaceEach(null, *, *, *, *) = null
    6662     *  StringUtils.replaceEach("", *, *, *, *) = ""
    6663     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
    6664     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
    6665     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
    6666     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
    6667     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
    6668     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
    6669     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
    6670     *  (example of how it repeats)
    6671     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
    6672     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
    6673     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
    6674     * </pre>
    6675     *
    6676     * @param text
    6677     *            text to search and replace in, no-op if null
    6678     * @param searchList
    6679     *            the Strings to search for, no-op if null
    6680     * @param replacementList
    6681     *            the Strings to replace them with, no-op if null
    6682     * @param repeat if true, then replace repeatedly
    6683     *       until there are no more possible replacements or timeToLive < 0
    6684     * @param timeToLive
    6685     *            if less than 0 then there is a circular reference and endless
    6686     *            loop
    6687     * @return the text with any replacements processed, {@code null} if
    6688     *         null String input
    6689     * @throws IllegalStateException
    6690     *             if the search is repeating and there is an endless loop due
    6691     *             to outputs of one being inputs to another
    6692     * @throws IllegalArgumentException
    6693     *             if the lengths of the arrays are not the same (null is ok,
    6694     *             and/or size 0)
    6695     * @since 2.4
    6696     */
    6697    private static String replaceEach(
    6698            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
    6699
    6700        // mchyzer Performance note: This creates very few new objects (one major goal)
    6701        // let me know if there are performance requests, we can create a harness to measure
    6702
    6703        // if recursing, this shouldn't be less than 0
    6704        if (timeToLive < 0) {
    6705            final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
    6706            final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
    6707            searchSet.retainAll(replacementSet);
    6708            if (!searchSet.isEmpty()) {
    6709                throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
    6710                        "output of one loop is the input of another");
    6711            }
    6712        }
    6713
    6714        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || (ArrayUtils.isNotEmpty(searchList) && timeToLive == -1)) {
    6715            return text;
    6716        }
    6717
    6718        final int searchLength = searchList.length;
    6719        final int replacementLength = replacementList.length;
    6720
    6721        // make sure lengths are ok, these need to be equal
    6722        if (searchLength != replacementLength) {
    6723            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    6724                + searchLength
    6725                + " vs "
    6726                + replacementLength);
    6727        }
    6728
    6729        // keep track of which still have matches
    6730        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    6731
    6732        // index on index that the match was found
    6733        int textIndex = -1;
    6734        int replaceIndex = -1;
    6735        int tempIndex = -1;
    6736
    6737        // index of replace array that will replace the search string found
    6738        // NOTE: logic duplicated below START
    6739        for (int i = 0; i < searchLength; i++) {
    6740            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6741                continue;
    6742            }
    6743            tempIndex = text.indexOf(searchList[i]);
    6744
    6745            // see if we need to keep searching for this
    6746            if (tempIndex == -1) {
    6747                noMoreMatchesForReplIndex[i] = true;
    6748            } else if (textIndex == -1 || tempIndex < textIndex) {
    6749                textIndex = tempIndex;
    6750                replaceIndex = i;
    6751            }
    6752        }
    6753        // NOTE: logic mostly below END
    6754
    6755        // no search strings found, we are done
    6756        if (textIndex == -1) {
    6757            return text;
    6758        }
    6759
    6760        int start = 0;
    6761
    6762        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
    6763        int increase = 0;
    6764
    6765        // count the replacement text elements that are larger than their corresponding text being replaced
    6766        for (int i = 0; i < searchList.length; i++) {
    6767            if (searchList[i] == null || replacementList[i] == null) {
    6768                continue;
    6769            }
    6770            final int greater = replacementList[i].length() - searchList[i].length();
    6771            if (greater > 0) {
    6772                increase += 3 * greater; // assume 3 matches
    6773            }
    6774        }
    6775        // have upper-bound at 20% increase, then let Java take over
    6776        increase = Math.min(increase, text.length() / 5);
    6777
    6778        final StringBuilder buf = new StringBuilder(text.length() + increase);
    6779
    6780        while (textIndex != -1) {
    6781
    6782            for (int i = start; i < textIndex; i++) {
    6783                buf.append(text.charAt(i));
    6784            }
    6785            buf.append(replacementList[replaceIndex]);
    6786
    6787            start = textIndex + searchList[replaceIndex].length();
    6788
    6789            textIndex = -1;
    6790            replaceIndex = -1;
    6791            // find the next earliest match
    6792            // NOTE: logic mostly duplicated above START
    6793            for (int i = 0; i < searchLength; i++) {
    6794                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
    6795                        searchList[i].isEmpty() || replacementList[i] == null) {
    6796                    continue;
    6797                }
    6798                tempIndex = text.indexOf(searchList[i], start);
    6799
    6800                // see if we need to keep searching for this
    6801                if (tempIndex == -1) {
    6802                    noMoreMatchesForReplIndex[i] = true;
    6803                } else if (textIndex == -1 || tempIndex < textIndex) {
    6804                    textIndex = tempIndex;
    6805                    replaceIndex = i;
    6806                }
    6807            }
    6808            // NOTE: logic duplicated above END
    6809
    6810        }
    6811        final int textLength = text.length();
    6812        for (int i = start; i < textLength; i++) {
    6813            buf.append(text.charAt(i));
    6814        }
    6815        final String result = buf.toString();
    6816        if (!repeat) {
    6817            return result;
    6818        }
    6819
    6820        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    6821    }
    6822
    6823    /**
    6824     * <p>
    6825     * Replaces all occurrences of Strings within another String.
    6826     * </p>
    6827     *
    6828     * <p>
    6829     * A {@code null} reference passed to this method is a no-op, or if
    6830     * any "search string" or "string to replace" is null, that replace will be
    6831     * ignored.
    6832     * </p>
    6833     *
    6834     * <pre>
    6835     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
    6836     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
    6837     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
    6838     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
    6839     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
    6840     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
    6841     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
    6842     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
    6843     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
    6844     *  (example of how it repeats)
    6845     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
    6846     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
    6847     * </pre>
    6848     *
    6849     * @param text
    6850     *            text to search and replace in, no-op if null
    6851     * @param searchList
    6852     *            the Strings to search for, no-op if null
    6853     * @param replacementList
    6854     *            the Strings to replace them with, no-op if null
    6855     * @return the text with any replacements processed, {@code null} if
    6856     *         null String input
    6857     * @throws IllegalStateException
    6858     *             if the search is repeating and there is an endless loop due
    6859     *             to outputs of one being inputs to another
    6860     * @throws IllegalArgumentException
    6861     *             if the lengths of the arrays are not the same (null is ok,
    6862     *             and/or size 0)
    6863     * @since 2.4
    6864     */
    6865    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
    6866        // timeToLive should be 0 if not used or nothing to replace, else it's
    6867        // the length of the replace array
    6868        final int timeToLive = searchList == null ? 0 : searchList.length;
    6869        return replaceEach(text, searchList, replacementList, true, timeToLive);
    6870    }
    6871
    6872    /**
    6873     * <p>Replaces the first substring of the text string that matches the given regular expression
    6874     * with the given replacement.</p>
    6875     *
    6876     * This method is a {@code null} safe equivalent to:
    6877     * <ul>
    6878     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
    6879     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
    6880     * </ul>
    6881     *
    6882     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6883     *
    6884     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    6885     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6886     * DOTALL is also known as single-line mode in Perl.</p>
    6887     *
    6888     * <pre>
    6889     * StringUtils.replaceFirst(null, *, *)       = null
    6890     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
    6891     * StringUtils.replaceFirst("any", *, null)   = "any"
    6892     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
    6893     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
    6894     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
    6895     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
    6896     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
    6897     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    6898     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
    6899     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
    6900     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
    6901     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
    6902     * </pre>
    6903     *
    6904     * @param text  text to search and replace in, may be null
    6905     * @param regex  the regular expression to which this string is to be matched
    6906     * @param replacement  the string to be substituted for the first match
    6907     * @return  the text with the first replacement processed,
    6908     *              {@code null} if null String input
    6909     *
    6910     * @throws  java.util.regex.PatternSyntaxException
    6911     *              if the regular expression's syntax is invalid
    6912     *
    6913     * @see String#replaceFirst(String, String)
    6914     * @see java.util.regex.Pattern
    6915     * @see java.util.regex.Pattern#DOTALL
    6916     * @since 3.5
    6917     *
    6918     * @deprecated Moved to RegExUtils.
    6919     */
    6920    @Deprecated
    6921    public static String replaceFirst(final String text, final String regex, final String replacement) {
    6922        return RegExUtils.replaceFirst(text, regex, replacement);
    6923    }
    6924
    6925    /**
    6926    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
    6927    *
    6928    * <p>A {@code null} reference passed to this method is a no-op.</p>
    6929    *
    6930    * <pre>
    6931    * StringUtils.replaceIgnoreCase(null, *, *)        = null
    6932    * StringUtils.replaceIgnoreCase("", *, *)          = ""
    6933    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
    6934    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
    6935    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
    6936    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
    6937    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
    6938    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
    6939    * </pre>
    6940    *
    6941    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6942    * @param text  text to search and replace in, may be null
    6943    * @param searchString  the String to search for (case insensitive), may be null
    6944    * @param replacement  the String to replace it with, may be null
    6945    * @return the text with any replacements processed,
    6946    *  {@code null} if null String input
    6947    * @since 3.5
    6948    */
    6949   public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
    6950       return replaceIgnoreCase(text, searchString, replacement, -1);
    6951   }
    6952
    6953    /**
    6954     * <p>Case insensitively replaces a String with another String inside a larger String,
    6955     * for the first {@code max} values of the search String.</p>
    6956     *
    6957     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6958     *
    6959     * <pre>
    6960     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
    6961     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
    6962     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
    6963     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
    6964     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
    6965     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
    6966     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
    6967     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
    6968     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
    6969     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
    6970     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
    6971     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
    6972     * </pre>
    6973     *
    6974     * @param text  text to search and replace in, may be null
    6975     * @param searchString  the String to search for (case insensitive), may be null
    6976     * @param replacement  the String to replace it with, may be null
    6977     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6978     * @return the text with any replacements processed,
    6979     *  {@code null} if null String input
    6980     * @since 3.5
    6981     */
    6982    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
    6983        return replace(text, searchString, replacement, max, true);
    6984    }
    6985
    6986    /**
    6987     * <p>Replaces a String with another String inside a larger String, once.</p>
    6988     *
    6989     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6990     *
    6991     * <pre>
    6992     * StringUtils.replaceOnce(null, *, *)        = null
    6993     * StringUtils.replaceOnce("", *, *)          = ""
    6994     * StringUtils.replaceOnce("any", null, *)    = "any"
    6995     * StringUtils.replaceOnce("any", *, null)    = "any"
    6996     * StringUtils.replaceOnce("any", "", *)      = "any"
    6997     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    6998     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    6999     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    7000     * </pre>
    7001     *
    7002     * @see #replace(String text, String searchString, String replacement, int max)
    7003     * @param text  text to search and replace in, may be null
    7004     * @param searchString  the String to search for, may be null
    7005     * @param replacement  the String to replace with, may be null
    7006     * @return the text with any replacements processed,
    7007     *  {@code null} if null String input
    7008     */
    7009    public static String replaceOnce(final String text, final String searchString, final String replacement) {
    7010        return replace(text, searchString, replacement, 1);
    7011    }
    7012
    7013    /**
    7014     * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
    7015     *
    7016     * <p>A {@code null} reference passed to this method is a no-op.</p>
    7017     *
    7018     * <pre>
    7019     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
    7020     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
    7021     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
    7022     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
    7023     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
    7024     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
    7025     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
    7026     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
    7027     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
    7028     * </pre>
    7029     *
    7030     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    7031     * @param text  text to search and replace in, may be null
    7032     * @param searchString  the String to search for (case insensitive), may be null
    7033     * @param replacement  the String to replace with, may be null
    7034     * @return the text with any replacements processed,
    7035     *  {@code null} if null String input
    7036     * @since 3.5
    7037     */
    7038    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
    7039        return replaceIgnoreCase(text, searchString, replacement, 1);
    7040    }
    7041
    7042    /**
    7043     * <p>Replaces each substring of the source String that matches the given regular expression with the given
    7044     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p>
    7045     *
    7046     * This call is a {@code null} safe equivalent to:
    7047     * <ul>
    7048     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
    7049     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
    7050     * </ul>
    7051     *
    7052     * <p>A {@code null} reference passed to this method is a no-op.</p>
    7053     *
    7054     * <pre>
    7055     * StringUtils.replacePattern(null, *, *)       = null
    7056     * StringUtils.replacePattern("any", (String) null, *)   = "any"
    7057     * StringUtils.replacePattern("any", *, null)   = "any"
    7058     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
    7059     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
    7060     * StringUtils.replacePattern("", ".+", "zzz")  = ""
    7061     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
    7062     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
    7063     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    7064     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    7065     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    7066     * </pre>
    7067     *
    7068     * @param source
    7069     *            the source string
    7070     * @param regex
    7071     *            the regular expression to which this string is to be matched
    7072     * @param replacement
    7073     *            the string to be substituted for each match
    7074     * @return The resulting {@code String}
    7075     * @see #replaceAll(String, String, String)
    7076     * @see String#replaceAll(String, String)
    7077     * @see Pattern#DOTALL
    7078     * @since 3.2
    7079     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    7080     *
    7081     * @deprecated Moved to RegExUtils.
    7082     */
    7083    @Deprecated
    7084    public static String replacePattern(final String source, final String regex, final String replacement) {
    7085        return RegExUtils.replacePattern(source, regex, replacement);
    7086    }
    7087
    7088    /**
    7089     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
    7090     *
    7091     * <p>A {@code null} String returns {@code null}.</p>
    7092     *
    7093     * <pre>
    7094     * StringUtils.reverse(null)  = null
    7095     * StringUtils.reverse("")    = ""
    7096     * StringUtils.reverse("bat") = "tab"
    7097     * </pre>
    7098     *
    7099     * @param str  the String to reverse, may be null
    7100     * @return the reversed String, {@code null} if null String input
    7101     */
    7102    public static String reverse(final String str) {
    7103        if (str == null) {
    7104            return null;
    7105        }
    7106        return new StringBuilder(str).reverse().toString();
    7107    }
    7108
    7109    /**
    7110     * <p>Reverses a String that is delimited by a specific character.</p>
    7111     *
    7112     * <p>The Strings between the delimiters are not reversed.
    7113     * Thus java.lang.String becomes String.lang.java (if the delimiter
    7114     * is {@code '.'}).</p>
    7115     *
    7116     * <pre>
    7117     * StringUtils.reverseDelimited(null, *)      = null
    7118     * StringUtils.reverseDelimited("", *)        = ""
    7119     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    7120     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    7121     * </pre>
    7122     *
    7123     * @param str  the String to reverse, may be null
    7124     * @param separatorChar  the separator character to use
    7125     * @return the reversed String, {@code null} if null String input
    7126     * @since 2.0
    7127     */
    7128    public static String reverseDelimited(final String str, final char separatorChar) {
    7129        if (str == null) {
    7130            return null;
    7131        }
    7132        // could implement manually, but simple way is to reuse other,
    7133        // probably slower, methods.
    7134        final String[] strs = split(str, separatorChar);
    7135        ArrayUtils.reverse(strs);
    7136        return join(strs, separatorChar);
    7137    }
    7138
    7139    /**
    7140     * <p>Gets the rightmost {@code len} characters of a String.</p>
    7141     *
    7142     * <p>If {@code len} characters are not available, or the String
    7143     * is {@code null}, the String will be returned without an
    7144     * an exception. An empty String is returned if len is negative.</p>
    7145     *
    7146     * <pre>
    7147     * StringUtils.right(null, *)    = null
    7148     * StringUtils.right(*, -ve)     = ""
    7149     * StringUtils.right("", *)      = ""
    7150     * StringUtils.right("abc", 0)   = ""
    7151     * StringUtils.right("abc", 2)   = "bc"
    7152     * StringUtils.right("abc", 4)   = "abc"
    7153     * </pre>
    7154     *
    7155     * @param str  the String to get the rightmost characters from, may be null
    7156     * @param len  the length of the required String
    7157     * @return the rightmost characters, {@code null} if null String input
    7158     */
    7159    public static String right(final String str, final int len) {
    7160        if (str == null) {
    7161            return null;
    7162        }
    7163        if (len < 0) {
    7164            return EMPTY;
    7165        }
    7166        if (str.length() <= len) {
    7167            return str;
    7168        }
    7169        return str.substring(str.length() - len);
    7170    }
    7171
    7172    /**
    7173     * <p>Right pad a String with spaces (' ').</p>
    7174     *
    7175     * <p>The String is padded to the size of {@code size}.</p>
    7176     *
    7177     * <pre>
    7178     * StringUtils.rightPad(null, *)   = null
    7179     * StringUtils.rightPad("", 3)     = "   "
    7180     * StringUtils.rightPad("bat", 3)  = "bat"
    7181     * StringUtils.rightPad("bat", 5)  = "bat  "
    7182     * StringUtils.rightPad("bat", 1)  = "bat"
    7183     * StringUtils.rightPad("bat", -1) = "bat"
    7184     * </pre>
    7185     *
    7186     * @param str  the String to pad out, may be null
    7187     * @param size  the size to pad to
    7188     * @return right padded String or original String if no padding is necessary,
    7189     *  {@code null} if null String input
    7190     */
    7191    public static String rightPad(final String str, final int size) {
    7192        return rightPad(str, size, ' ');
    7193    }
    7194
    7195    /**
    7196     * <p>Right pad a String with a specified character.</p>
    7197     *
    7198     * <p>The String is padded to the size of {@code size}.</p>
    7199     *
    7200     * <pre>
    7201     * StringUtils.rightPad(null, *, *)     = null
    7202     * StringUtils.rightPad("", 3, 'z')     = "zzz"
    7203     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    7204     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    7205     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    7206     * StringUtils.rightPad("bat", -1, 'z') = "bat"
    7207     * </pre>
    7208     *
    7209     * @param str  the String to pad out, may be null
    7210     * @param size  the size to pad to
    7211     * @param padChar  the character to pad with
    7212     * @return right padded String or original String if no padding is necessary,
    7213     *  {@code null} if null String input
    7214     * @since 2.0
    7215     */
    7216    public static String rightPad(final String str, final int size, final char padChar) {
    7217        if (str == null) {
    7218            return null;
    7219        }
    7220        final int pads = size - str.length();
    7221        if (pads <= 0) {
    7222            return str; // returns original String when possible
    7223        }
    7224        if (pads > PAD_LIMIT) {
    7225            return rightPad(str, size, String.valueOf(padChar));
    7226        }
    7227        return str.concat(repeat(padChar, pads));
    7228    }
    7229
    7230    /**
    7231     * <p>Right pad a String with a specified String.</p>
    7232     *
    7233     * <p>The String is padded to the size of {@code size}.</p>
    7234     *
    7235     * <pre>
    7236     * StringUtils.rightPad(null, *, *)      = null
    7237     * StringUtils.rightPad("", 3, "z")      = "zzz"
    7238     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    7239     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    7240     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    7241     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    7242     * StringUtils.rightPad("bat", -1, "yz") = "bat"
    7243     * StringUtils.rightPad("bat", 5, null)  = "bat  "
    7244     * StringUtils.rightPad("bat", 5, "")    = "bat  "
    7245     * </pre>
    7246     *
    7247     * @param str  the String to pad out, may be null
    7248     * @param size  the size to pad to
    7249     * @param padStr  the String to pad with, null or empty treated as single space
    7250     * @return right padded String or original String if no padding is necessary,
    7251     *  {@code null} if null String input
    7252     */
    7253    public static String rightPad(final String str, final int size, String padStr) {
    7254        if (str == null) {
    7255            return null;
    7256        }
    7257        if (isEmpty(padStr)) {
    7258            padStr = SPACE;
    7259        }
    7260        final int padLen = padStr.length();
    7261        final int strLen = str.length();
    7262        final int pads = size - strLen;
    7263        if (pads <= 0) {
    7264            return str; // returns original String when possible
    7265        }
    7266        if (padLen == 1 && pads <= PAD_LIMIT) {
    7267            return rightPad(str, size, padStr.charAt(0));
    7268        }
    7269
    7270        if (pads == padLen) {
    7271            return str.concat(padStr);
    7272        } else if (pads < padLen) {
    7273            return str.concat(padStr.substring(0, pads));
    7274        } else {
    7275            final char[] padding = new char[pads];
    7276            final char[] padChars = padStr.toCharArray();
    7277            for (int i = 0; i < pads; i++) {
    7278                padding[i] = padChars[i % padLen];
    7279            }
    7280            return str.concat(new String(padding));
    7281        }
    7282    }
    7283
    7284    /**
    7285     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
    7286     * <ul>
    7287     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
    7288     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
    7289     * </ul>
    7290     *
    7291     * <pre>
    7292     * StringUtils.rotate(null, *)        = null
    7293     * StringUtils.rotate("", *)          = ""
    7294     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
    7295     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
    7296     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
    7297     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
    7298     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
    7299     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
    7300     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
    7301     * </pre>
    7302     *
    7303     * @param str  the String to rotate, may be null
    7304     * @param shift  number of time to shift (positive : right shift, negative : left shift)
    7305     * @return the rotated String,
    7306     *          or the original String if {@code shift == 0},
    7307     *          or {@code null} if null String input
    7308     * @since 3.5
    7309     */
    7310    public static String rotate(final String str, final int shift) {
    7311        if (str == null) {
    7312            return null;
    7313        }
    7314
    7315        final int strLen = str.length();
    7316        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
    7317            return str;
    7318        }
    7319
    7320        final StringBuilder builder = new StringBuilder(strLen);
    7321        final int offset = - (shift % strLen);
    7322        builder.append(substring(str, offset));
    7323        builder.append(substring(str, 0, offset));
    7324        return builder.toString();
    7325    }
    7326
    7327    /**
    7328     * <p>Splits the provided text into an array, using whitespace as the
    7329     * separator.
    7330     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7331     *
    7332     * <p>The separator is not included in the returned String array.
    7333     * Adjacent separators are treated as one separator.
    7334     * For more control over the split use the StrTokenizer class.</p>
    7335     *
    7336     * <p>A {@code null} input String returns {@code null}.</p>
    7337     *
    7338     * <pre>
    7339     * StringUtils.split(null)       = null
    7340     * StringUtils.split("")         = []
    7341     * StringUtils.split("abc def")  = ["abc", "def"]
    7342     * StringUtils.split("abc  def") = ["abc", "def"]
    7343     * StringUtils.split(" abc ")    = ["abc"]
    7344     * </pre>
    7345     *
    7346     * @param str  the String to parse, may be null
    7347     * @return an array of parsed Strings, {@code null} if null String input
    7348     */
    7349    public static String[] split(final String str) {
    7350        return split(str, null, -1);
    7351    }
    7352
    7353    /**
    7354     * <p>Splits the provided text into an array, separator specified.
    7355     * This is an alternative to using StringTokenizer.</p>
    7356     *
    7357     * <p>The separator is not included in the returned String array.
    7358     * Adjacent separators are treated as one separator.
    7359     * For more control over the split use the StrTokenizer class.</p>
    7360     *
    7361     * <p>A {@code null} input String returns {@code null}.</p>
    7362     *
    7363     * <pre>
    7364     * StringUtils.split(null, *)         = null
    7365     * StringUtils.split("", *)           = []
    7366     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    7367     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    7368     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    7369     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    7370     * </pre>
    7371     *
    7372     * @param str  the String to parse, may be null
    7373     * @param separatorChar  the character used as the delimiter
    7374     * @return an array of parsed Strings, {@code null} if null String input
    7375     * @since 2.0
    7376     */
    7377    public static String[] split(final String str, final char separatorChar) {
    7378        return splitWorker(str, separatorChar, false);
    7379    }
    7380
    7381    /**
    7382     * <p>Splits the provided text into an array, separators specified.
    7383     * This is an alternative to using StringTokenizer.</p>
    7384     *
    7385     * <p>The separator is not included in the returned String array.
    7386     * Adjacent separators are treated as one separator.
    7387     * For more control over the split use the StrTokenizer class.</p>
    7388     *
    7389     * <p>A {@code null} input String returns {@code null}.
    7390     * A {@code null} separatorChars splits on whitespace.</p>
    7391     *
    7392     * <pre>
    7393     * StringUtils.split(null, *)         = null
    7394     * StringUtils.split("", *)           = []
    7395     * StringUtils.split("abc def", null) = ["abc", "def"]
    7396     * StringUtils.split("abc def", " ")  = ["abc", "def"]
    7397     * StringUtils.split("abc  def", " ") = ["abc", "def"]
    7398     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    7399     * </pre>
    7400     *
    7401     * @param str  the String to parse, may be null
    7402     * @param separatorChars  the characters used as the delimiters,
    7403     *  {@code null} splits on whitespace
    7404     * @return an array of parsed Strings, {@code null} if null String input
    7405     */
    7406    public static String[] split(final String str, final String separatorChars) {
    7407        return splitWorker(str, separatorChars, -1, false);
    7408    }
    7409
    7410    /**
    7411     * <p>Splits the provided text into an array with a maximum length,
    7412     * separators specified.</p>
    7413     *
    7414     * <p>The separator is not included in the returned String array.
    7415     * Adjacent separators are treated as one separator.</p>
    7416     *
    7417     * <p>A {@code null} input String returns {@code null}.
    7418     * A {@code null} separatorChars splits on whitespace.</p>
    7419     *
    7420     * <p>If more than {@code max} delimited substrings are found, the last
    7421     * returned string includes all characters after the first {@code max - 1}
    7422     * returned strings (including separator characters).</p>
    7423     *
    7424     * <pre>
    7425     * StringUtils.split(null, *, *)            = null
    7426     * StringUtils.split("", *, *)              = []
    7427     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
    7428     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
    7429     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7430     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7431     * </pre>
    7432     *
    7433     * @param str  the String to parse, may be null
    7434     * @param separatorChars  the characters used as the delimiters,
    7435     *  {@code null} splits on whitespace
    7436     * @param max  the maximum number of elements to include in the
    7437     *  array. A zero or negative value implies no limit
    7438     * @return an array of parsed Strings, {@code null} if null String input
    7439     */
    7440    public static String[] split(final String str, final String separatorChars, final int max) {
    7441        return splitWorker(str, separatorChars, max, false);
    7442    }
    7443
    7444    /**
    7445     * <p>Splits a String by Character type as returned by
    7446     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7447     * characters of the same type are returned as complete tokens.
    7448     * <pre>
    7449     * StringUtils.splitByCharacterType(null)         = null
    7450     * StringUtils.splitByCharacterType("")           = []
    7451     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7452     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7453     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7454     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    7455     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    7456     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    7457     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    7458     * </pre>
    7459     * @param str the String to split, may be {@code null}
    7460     * @return an array of parsed Strings, {@code null} if null String input
    7461     * @since 2.4
    7462     */
    7463    public static String[] splitByCharacterType(final String str) {
    7464        return splitByCharacterType(str, false);
    7465    }
    7466
    7467    /**
    7468     * <p>Splits a String by Character type as returned by
    7469     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7470     * characters of the same type are returned as complete tokens, with the
    7471     * following exception: if {@code camelCase} is {@code true},
    7472     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
    7473     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
    7474     * will belong to the following token rather than to the preceding, if any,
    7475     * {@code Character.UPPERCASE_LETTER} token.
    7476     * @param str the String to split, may be {@code null}
    7477     * @param camelCase whether to use so-called "camel-case" for letter types
    7478     * @return an array of parsed Strings, {@code null} if null String input
    7479     * @since 2.4
    7480     */
    7481    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
    7482        if (str == null) {
    7483            return null;
    7484        }
    7485        if (str.isEmpty()) {
    7486            return ArrayUtils.EMPTY_STRING_ARRAY;
    7487        }
    7488        final char[] c = str.toCharArray();
    7489        final List<String> list = new ArrayList<>();
    7490        int tokenStart = 0;
    7491        int currentType = Character.getType(c[tokenStart]);
    7492        for (int pos = tokenStart + 1; pos < c.length; pos++) {
    7493            final int type = Character.getType(c[pos]);
    7494            if (type == currentType) {
    7495                continue;
    7496            }
    7497            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    7498                final int newTokenStart = pos - 1;
    7499                if (newTokenStart != tokenStart) {
    7500                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    7501                    tokenStart = newTokenStart;
    7502                }
    7503            } else {
    7504                list.add(new String(c, tokenStart, pos - tokenStart));
    7505                tokenStart = pos;
    7506            }
    7507            currentType = type;
    7508        }
    7509        list.add(new String(c, tokenStart, c.length - tokenStart));
    7510        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7511    }
    7512
    7513    /**
    7514     * <p>Splits a String by Character type as returned by
    7515     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7516     * characters of the same type are returned as complete tokens, with the
    7517     * following exception: the character of type
    7518     * {@code Character.UPPERCASE_LETTER}, if any, immediately
    7519     * preceding a token of type {@code Character.LOWERCASE_LETTER}
    7520     * will belong to the following token rather than to the preceding, if any,
    7521     * {@code Character.UPPERCASE_LETTER} token.
    7522     * <pre>
    7523     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    7524     * StringUtils.splitByCharacterTypeCamelCase("")           = []
    7525     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7526     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7527     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7528     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    7529     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    7530     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    7531     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    7532     * </pre>
    7533     * @param str the String to split, may be {@code null}
    7534     * @return an array of parsed Strings, {@code null} if null String input
    7535     * @since 2.4
    7536     */
    7537    public static String[] splitByCharacterTypeCamelCase(final String str) {
    7538        return splitByCharacterType(str, true);
    7539    }
    7540
    7541    /**
    7542     * <p>Splits the provided text into an array, separator string specified.</p>
    7543     *
    7544     * <p>The separator(s) will not be included in the returned String array.
    7545     * Adjacent separators are treated as one separator.</p>
    7546     *
    7547     * <p>A {@code null} input String returns {@code null}.
    7548     * A {@code null} separator splits on whitespace.</p>
    7549     *
    7550     * <pre>
    7551     * StringUtils.splitByWholeSeparator(null, *)               = null
    7552     * StringUtils.splitByWholeSeparator("", *)                 = []
    7553     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    7554     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    7555     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7556     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7557     * </pre>
    7558     *
    7559     * @param str  the String to parse, may be null
    7560     * @param separator  String containing the String to be used as a delimiter,
    7561     *  {@code null} splits on whitespace
    7562     * @return an array of parsed Strings, {@code null} if null String was input
    7563     */
    7564    public static String[] splitByWholeSeparator(final String str, final String separator) {
    7565        return splitByWholeSeparatorWorker(str, separator, -1, false);
    7566    }
    7567
    7568    /**
    7569     * <p>Splits the provided text into an array, separator string specified.
    7570     * Returns a maximum of {@code max} substrings.</p>
    7571     *
    7572     * <p>The separator(s) will not be included in the returned String array.
    7573     * Adjacent separators are treated as one separator.</p>
    7574     *
    7575     * <p>A {@code null} input String returns {@code null}.
    7576     * A {@code null} separator splits on whitespace.</p>
    7577     *
    7578     * <pre>
    7579     * StringUtils.splitByWholeSeparator(null, *, *)               = null
    7580     * StringUtils.splitByWholeSeparator("", *, *)                 = []
    7581     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7582     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    7583     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7584     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7585     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7586     * </pre>
    7587     *
    7588     * @param str  the String to parse, may be null
    7589     * @param separator  String containing the String to be used as a delimiter,
    7590     *  {@code null} splits on whitespace
    7591     * @param max  the maximum number of elements to include in the returned
    7592     *  array. A zero or negative value implies no limit.
    7593     * @return an array of parsed Strings, {@code null} if null String was input
    7594     */
    7595    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
    7596        return splitByWholeSeparatorWorker(str, separator, max, false);
    7597    }
    7598
    7599    /**
    7600     * <p>Splits the provided text into an array, separator string specified. </p>
    7601     *
    7602     * <p>The separator is not included in the returned String array.
    7603     * Adjacent separators are treated as separators for empty tokens.
    7604     * For more control over the split use the StrTokenizer class.</p>
    7605     *
    7606     * <p>A {@code null} input String returns {@code null}.
    7607     * A {@code null} separator splits on whitespace.</p>
    7608     *
    7609     * <pre>
    7610     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    7611     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    7612     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    7613     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    7614     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7615     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7616     * </pre>
    7617     *
    7618     * @param str  the String to parse, may be null
    7619     * @param separator  String containing the String to be used as a delimiter,
    7620     *  {@code null} splits on whitespace
    7621     * @return an array of parsed Strings, {@code null} if null String was input
    7622     * @since 2.4
    7623     */
    7624    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
    7625        return splitByWholeSeparatorWorker(str, separator, -1, true);
    7626    }
    7627
    7628    /**
    7629     * <p>Splits the provided text into an array, separator string specified.
    7630     * Returns a maximum of {@code max} substrings.</p>
    7631     *
    7632     * <p>The separator is not included in the returned String array.
    7633     * Adjacent separators are treated as separators for empty tokens.
    7634     * For more control over the split use the StrTokenizer class.</p>
    7635     *
    7636     * <p>A {@code null} input String returns {@code null}.
    7637     * A {@code null} separator splits on whitespace.</p>
    7638     *
    7639     * <pre>
    7640     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    7641     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    7642     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7643     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    7644     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7645     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7646     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7647     * </pre>
    7648     *
    7649     * @param str  the String to parse, may be null
    7650     * @param separator  String containing the String to be used as a delimiter,
    7651     *  {@code null} splits on whitespace
    7652     * @param max  the maximum number of elements to include in the returned
    7653     *  array. A zero or negative value implies no limit.
    7654     * @return an array of parsed Strings, {@code null} if null String was input
    7655     * @since 2.4
    7656     */
    7657    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
    7658        return splitByWholeSeparatorWorker(str, separator, max, true);
    7659    }
    7660
    7661    /**
    7662     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
    7663     *
    7664     * @param str  the String to parse, may be {@code null}
    7665     * @param separator  String containing the String to be used as a delimiter,
    7666     *  {@code null} splits on whitespace
    7667     * @param max  the maximum number of elements to include in the returned
    7668     *  array. A zero or negative value implies no limit.
    7669     * @param preserveAllTokens if {@code true}, adjacent separators are
    7670     * treated as empty token separators; if {@code false}, adjacent
    7671     * separators are treated as one separator.
    7672     * @return an array of parsed Strings, {@code null} if null String input
    7673     * @since 2.4
    7674     */
    7675    private static String[] splitByWholeSeparatorWorker(
    7676            final String str, final String separator, final int max, final boolean preserveAllTokens) {
    7677        if (str == null) {
    7678            return null;
    7679        }
    7680
    7681        final int len = str.length();
    7682
    7683        if (len == 0) {
    7684            return ArrayUtils.EMPTY_STRING_ARRAY;
    7685        }
    7686
    7687        if (separator == null || EMPTY.equals(separator)) {
    7688            // Split on whitespace.
    7689            return splitWorker(str, null, max, preserveAllTokens);
    7690        }
    7691
    7692        final int separatorLength = separator.length();
    7693
    7694        final ArrayList<String> substrings = new ArrayList<>();
    7695        int numberOfSubstrings = 0;
    7696        int beg = 0;
    7697        int end = 0;
    7698        while (end < len) {
    7699            end = str.indexOf(separator, beg);
    7700
    7701            if (end > -1) {
    7702                if (end > beg) {
    7703                    numberOfSubstrings += 1;
    7704
    7705                    if (numberOfSubstrings == max) {
    7706                        end = len;
    7707                        substrings.add(str.substring(beg));
    7708                    } else {
    7709                        // The following is OK, because String.substring( beg, end ) excludes
    7710                        // the character at the position 'end'.
    7711                        substrings.add(str.substring(beg, end));
    7712
    7713                        // Set the starting point for the next search.
    7714                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    7715                        // which is the right calculation:
    7716                        beg = end + separatorLength;
    7717                    }
    7718                } else {
    7719                    // We found a consecutive occurrence of the separator, so skip it.
    7720                    if (preserveAllTokens) {
    7721                        numberOfSubstrings += 1;
    7722                        if (numberOfSubstrings == max) {
    7723                            end = len;
    7724                            substrings.add(str.substring(beg));
    7725                        } else {
    7726                            substrings.add(EMPTY);
    7727                        }
    7728                    }
    7729                    beg = end + separatorLength;
    7730                }
    7731            } else {
    7732                // String.substring( beg ) goes from 'beg' to the end of the String.
    7733                substrings.add(str.substring(beg));
    7734                end = len;
    7735            }
    7736        }
    7737
    7738        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7739    }
    7740
    7741    /**
    7742     * <p>Splits the provided text into an array, using whitespace as the
    7743     * separator, preserving all tokens, including empty tokens created by
    7744     * adjacent separators. This is an alternative to using StringTokenizer.
    7745     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7746     *
    7747     * <p>The separator is not included in the returned String array.
    7748     * Adjacent separators are treated as separators for empty tokens.
    7749     * For more control over the split use the StrTokenizer class.</p>
    7750     *
    7751     * <p>A {@code null} input String returns {@code null}.</p>
    7752     *
    7753     * <pre>
    7754     * StringUtils.splitPreserveAllTokens(null)       = null
    7755     * StringUtils.splitPreserveAllTokens("")         = []
    7756     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    7757     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    7758     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    7759     * </pre>
    7760     *
    7761     * @param str  the String to parse, may be {@code null}
    7762     * @return an array of parsed Strings, {@code null} if null String input
    7763     * @since 2.1
    7764     */
    7765    public static String[] splitPreserveAllTokens(final String str) {
    7766        return splitWorker(str, null, -1, true);
    7767    }
    7768
    7769    /**
    7770     * <p>Splits the provided text into an array, separator specified,
    7771     * preserving all tokens, including empty tokens created by adjacent
    7772     * separators. This is an alternative to using StringTokenizer.</p>
    7773     *
    7774     * <p>The separator is not included in the returned String array.
    7775     * Adjacent separators are treated as separators for empty tokens.
    7776     * For more control over the split use the StrTokenizer class.</p>
    7777     *
    7778     * <p>A {@code null} input String returns {@code null}.</p>
    7779     *
    7780     * <pre>
    7781     * StringUtils.splitPreserveAllTokens(null, *)         = null
    7782     * StringUtils.splitPreserveAllTokens("", *)           = []
    7783     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    7784     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    7785     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    7786     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    7787     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    7788     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    7789     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
    7790     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
    7791     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
    7792     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
    7793     * </pre>
    7794     *
    7795     * @param str  the String to parse, may be {@code null}
    7796     * @param separatorChar  the character used as the delimiter,
    7797     *  {@code null} splits on whitespace
    7798     * @return an array of parsed Strings, {@code null} if null String input
    7799     * @since 2.1
    7800     */
    7801    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
    7802        return splitWorker(str, separatorChar, true);
    7803    }
    7804
    7805    /**
    7806     * <p>Splits the provided text into an array, separators specified,
    7807     * preserving all tokens, including empty tokens created by adjacent
    7808     * separators. This is an alternative to using StringTokenizer.</p>
    7809     *
    7810     * <p>The separator is not included in the returned String array.
    7811     * Adjacent separators are treated as separators for empty tokens.
    7812     * For more control over the split use the StrTokenizer class.</p>
    7813     *
    7814     * <p>A {@code null} input String returns {@code null}.
    7815     * A {@code null} separatorChars splits on whitespace.</p>
    7816     *
    7817     * <pre>
    7818     * StringUtils.splitPreserveAllTokens(null, *)           = null
    7819     * StringUtils.splitPreserveAllTokens("", *)             = []
    7820     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    7821     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    7822     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
    7823     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    7824     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    7825     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    7826     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
    7827     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
    7828     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
    7829     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
    7830     * </pre>
    7831     *
    7832     * @param str  the String to parse, may be {@code null}
    7833     * @param separatorChars  the characters used as the delimiters,
    7834     *  {@code null} splits on whitespace
    7835     * @return an array of parsed Strings, {@code null} if null String input
    7836     * @since 2.1
    7837     */
    7838    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
    7839        return splitWorker(str, separatorChars, -1, true);
    7840    }
    7841
    7842    /**
    7843     * <p>Splits the provided text into an array with a maximum length,
    7844     * separators specified, preserving all tokens, including empty tokens
    7845     * created by adjacent separators.</p>
    7846     *
    7847     * <p>The separator is not included in the returned String array.
    7848     * Adjacent separators are treated as separators for empty tokens.
    7849     * Adjacent separators are treated as one separator.</p>
    7850     *
    7851     * <p>A {@code null} input String returns {@code null}.
    7852     * A {@code null} separatorChars splits on whitespace.</p>
    7853     *
    7854     * <p>If more than {@code max} delimited substrings are found, the last
    7855     * returned string includes all characters after the first {@code max - 1}
    7856     * returned strings (including separator characters).</p>
    7857     *
    7858     * <pre>
    7859     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    7860     * StringUtils.splitPreserveAllTokens("", *, *)              = []
    7861     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
    7862     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
    7863     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7864     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7865     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    7866     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    7867     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    7868     * </pre>
    7869     *
    7870     * @param str  the String to parse, may be {@code null}
    7871     * @param separatorChars  the characters used as the delimiters,
    7872     *  {@code null} splits on whitespace
    7873     * @param max  the maximum number of elements to include in the
    7874     *  array. A zero or negative value implies no limit
    7875     * @return an array of parsed Strings, {@code null} if null String input
    7876     * @since 2.1
    7877     */
    7878    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
    7879        return splitWorker(str, separatorChars, max, true);
    7880    }
    7881
    7882    /**
    7883     * Performs the logic for the {@code split} and
    7884     * {@code splitPreserveAllTokens} methods that do not return a
    7885     * maximum array length.
    7886     *
    7887     * @param str  the String to parse, may be {@code null}
    7888     * @param separatorChar the separate character
    7889     * @param preserveAllTokens if {@code true}, adjacent separators are
    7890     * treated as empty token separators; if {@code false}, adjacent
    7891     * separators are treated as one separator.
    7892     * @return an array of parsed Strings, {@code null} if null String input
    7893     */
    7894    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
    7895        // Performance tuned for 2.0 (JDK1.4)
    7896
    7897        if (str == null) {
    7898            return null;
    7899        }
    7900        final int len = str.length();
    7901        if (len == 0) {
    7902            return ArrayUtils.EMPTY_STRING_ARRAY;
    7903        }
    7904        final List<String> list = new ArrayList<>();
    7905        int i = 0;
    7906        int start = 0;
    7907        boolean match = false;
    7908        boolean lastMatch = false;
    7909        while (i < len) {
    7910            if (str.charAt(i) == separatorChar) {
    7911                if (match || preserveAllTokens) {
    7912                    list.add(str.substring(start, i));
    7913                    match = false;
    7914                    lastMatch = true;
    7915                }
    7916                start = ++i;
    7917                continue;
    7918            }
    7919            lastMatch = false;
    7920            match = true;
    7921            i++;
    7922        }
    7923        if (match || preserveAllTokens && lastMatch) {
    7924            list.add(str.substring(start, i));
    7925        }
    7926        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7927    }
    7928
    7929    /**
    7930     * Performs the logic for the {@code split} and
    7931     * {@code splitPreserveAllTokens} methods that return a maximum array
    7932     * length.
    7933     *
    7934     * @param str  the String to parse, may be {@code null}
    7935     * @param separatorChars the separate character
    7936     * @param max  the maximum number of elements to include in the
    7937     *  array. A zero or negative value implies no limit.
    7938     * @param preserveAllTokens if {@code true}, adjacent separators are
    7939     * treated as empty token separators; if {@code false}, adjacent
    7940     * separators are treated as one separator.
    7941     * @return an array of parsed Strings, {@code null} if null String input
    7942     */
    7943    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
    7944        // Performance tuned for 2.0 (JDK1.4)
    7945        // Direct code is quicker than StringTokenizer.
    7946        // Also, StringTokenizer uses isSpace() not isWhitespace()
    7947
    7948        if (str == null) {
    7949            return null;
    7950        }
    7951        final int len = str.length();
    7952        if (len == 0) {
    7953            return ArrayUtils.EMPTY_STRING_ARRAY;
    7954        }
    7955        final List<String> list = new ArrayList<>();
    7956        int sizePlus1 = 1;
    7957        int i = 0;
    7958        int start = 0;
    7959        boolean match = false;
    7960        boolean lastMatch = false;
    7961        if (separatorChars == null) {
    7962            // Null separator means use whitespace
    7963            while (i < len) {
    7964                if (Character.isWhitespace(str.charAt(i))) {
    7965                    if (match || preserveAllTokens) {
    7966                        lastMatch = true;
    7967                        if (sizePlus1++ == max) {
    7968                            i = len;
    7969                            lastMatch = false;
    7970                        }
    7971                        list.add(str.substring(start, i));
    7972                        match = false;
    7973                    }
    7974                    start = ++i;
    7975                    continue;
    7976                }
    7977                lastMatch = false;
    7978                match = true;
    7979                i++;
    7980            }
    7981        } else if (separatorChars.length() == 1) {
    7982            // Optimise 1 character case
    7983            final char sep = separatorChars.charAt(0);
    7984            while (i < len) {
    7985                if (str.charAt(i) == sep) {
    7986                    if (match || preserveAllTokens) {
    7987                        lastMatch = true;
    7988                        if (sizePlus1++ == max) {
    7989                            i = len;
    7990                            lastMatch = false;
    7991                        }
    7992                        list.add(str.substring(start, i));
    7993                        match = false;
    7994                    }
    7995                    start = ++i;
    7996                    continue;
    7997                }
    7998                lastMatch = false;
    7999                match = true;
    8000                i++;
    8001            }
    8002        } else {
    8003            // standard case
    8004            while (i < len) {
    8005                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    8006                    if (match || preserveAllTokens) {
    8007                        lastMatch = true;
    8008                        if (sizePlus1++ == max) {
    8009                            i = len;
    8010                            lastMatch = false;
    8011                        }
    8012                        list.add(str.substring(start, i));
    8013                        match = false;
    8014                    }
    8015                    start = ++i;
    8016                    continue;
    8017                }
    8018                lastMatch = false;
    8019                match = true;
    8020                i++;
    8021            }
    8022        }
    8023        if (match || preserveAllTokens && lastMatch) {
    8024            list.add(str.substring(start, i));
    8025        }
    8026        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    8027    }
    8028
    8029    /**
    8030     * <p>Check if a CharSequence starts with a specified prefix.</p>
    8031     *
    8032     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8033     * references are considered to be equal. The comparison is case sensitive.</p>
    8034     *
    8035     * <pre>
    8036     * StringUtils.startsWith(null, null)      = true
    8037     * StringUtils.startsWith(null, "abc")     = false
    8038     * StringUtils.startsWith("abcdef", null)  = false
    8039     * StringUtils.startsWith("abcdef", "abc") = true
    8040     * StringUtils.startsWith("ABCDEF", "abc") = false
    8041     * </pre>
    8042     *
    8043     * @see java.lang.String#startsWith(String)
    8044     * @param str  the CharSequence to check, may be null
    8045     * @param prefix the prefix to find, may be null
    8046     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
    8047     *  both {@code null}
    8048     * @since 2.4
    8049     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
    8050     */
    8051    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
    8052        return startsWith(str, prefix, false);
    8053    }
    8054
    8055    /**
    8056     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
    8057     *
    8058     * @see java.lang.String#startsWith(String)
    8059     * @param str  the CharSequence to check, may be null
    8060     * @param prefix the prefix to find, may be null
    8061     * @param ignoreCase indicates whether the compare should ignore case
    8062     *  (case insensitive) or not.
    8063     * @return {@code true} if the CharSequence starts with the prefix or
    8064     *  both {@code null}
    8065     */
    8066    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
    8067        if (str == null || prefix == null) {
    8068            return str == prefix;
    8069        }
    8070        // Get length once instead of twice in the unlikely case that it changes.
    8071        final int preLen = prefix.length();
    8072        if (preLen > str.length()) {
    8073            return false;
    8074        }
    8075        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen);
    8076    }
    8077
    8078    /**
    8079     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
    8080     *
    8081     * <pre>
    8082     * StringUtils.startsWithAny(null, null)      = false
    8083     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    8084     * StringUtils.startsWithAny("abcxyz", null)     = false
    8085     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
    8086     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    8087     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    8088     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
    8089     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
    8090     * </pre>
    8091     *
    8092     * @param sequence the CharSequence to check, may be null
    8093     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
    8094     * @see StringUtils#startsWith(CharSequence, CharSequence)
    8095     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    8096     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
    8097     * @since 2.5
    8098     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
    8099     */
    8100    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    8101        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    8102            return false;
    8103        }
    8104        for (final CharSequence searchString : searchStrings) {
    8105            if (startsWith(sequence, searchString)) {
    8106                return true;
    8107            }
    8108        }
    8109        return false;
    8110    }
    8111
    8112    /**
    8113     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
    8114     *
    8115     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8116     * references are considered to be equal. The comparison is case insensitive.</p>
    8117     *
    8118     * <pre>
    8119     * StringUtils.startsWithIgnoreCase(null, null)      = true
    8120     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    8121     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    8122     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    8123     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    8124     * </pre>
    8125     *
    8126     * @see java.lang.String#startsWith(String)
    8127     * @param str  the CharSequence to check, may be null
    8128     * @param prefix the prefix to find, may be null
    8129     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
    8130     *  both {@code null}
    8131     * @since 2.4
    8132     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
    8133     */
    8134    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
    8135        return startsWith(str, prefix, true);
    8136    }
    8137
    8138    /**
    8139     * <p>Strips whitespace from the start and end of a String.</p>
    8140     *
    8141     * <p>This is similar to {@link #trim(String)} but removes whitespace.
    8142     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8143     *
    8144     * <p>A {@code null} input String returns {@code null}.</p>
    8145     *
    8146     * <pre>
    8147     * StringUtils.strip(null)     = null
    8148     * StringUtils.strip("")       = ""
    8149     * StringUtils.strip("   ")    = ""
    8150     * StringUtils.strip("abc")    = "abc"
    8151     * StringUtils.strip("  abc")  = "abc"
    8152     * StringUtils.strip("abc  ")  = "abc"
    8153     * StringUtils.strip(" abc ")  = "abc"
    8154     * StringUtils.strip(" ab c ") = "ab c"
    8155     * </pre>
    8156     *
    8157     * @param str  the String to remove whitespace from, may be null
    8158     * @return the stripped String, {@code null} if null String input
    8159     */
    8160    public static String strip(final String str) {
    8161        return strip(str, null);
    8162    }
    8163
    8164    /**
    8165     * <p>Strips any of a set of characters from the start and end of a String.
    8166     * This is similar to {@link String#trim()} but allows the characters
    8167     * to be stripped to be controlled.</p>
    8168     *
    8169     * <p>A {@code null} input String returns {@code null}.
    8170     * An empty string ("") input returns the empty string.</p>
    8171     *
    8172     * <p>If the stripChars String is {@code null}, whitespace is
    8173     * stripped as defined by {@link Character#isWhitespace(char)}.
    8174     * Alternatively use {@link #strip(String)}.</p>
    8175     *
    8176     * <pre>
    8177     * StringUtils.strip(null, *)          = null
    8178     * StringUtils.strip("", *)            = ""
    8179     * StringUtils.strip("abc", null)      = "abc"
    8180     * StringUtils.strip("  abc", null)    = "abc"
    8181     * StringUtils.strip("abc  ", null)    = "abc"
    8182     * StringUtils.strip(" abc ", null)    = "abc"
    8183     * StringUtils.strip("  abcyx", "xyz") = "  abc"
    8184     * </pre>
    8185     *
    8186     * @param str  the String to remove characters from, may be null
    8187     * @param stripChars  the characters to remove, null treated as whitespace
    8188     * @return the stripped String, {@code null} if null String input
    8189     */
    8190    public static String strip(String str, final String stripChars) {
    8191        str = stripStart(str, stripChars);
    8192        return stripEnd(str, stripChars);
    8193    }
    8194
    8195    /**
    8196     * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
    8197     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
    8198     * <p>Note that ligatures will be left as is.</p>
    8199     *
    8200     * <pre>
    8201     * StringUtils.stripAccents(null)                = null
    8202     * StringUtils.stripAccents("")                  = ""
    8203     * StringUtils.stripAccents("control")           = "control"
    8204     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
    8205     * </pre>
    8206     *
    8207     * @param input String to be stripped
    8208     * @return input text with diacritics removed
    8209     *
    8210     * @since 3.0
    8211     */
    8212    // 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).
    8213    public static String stripAccents(final String input) {
    8214        if (input == null) {
    8215            return null;
    8216        }
    8217        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
    8218        convertRemainingAccentCharacters(decomposed);
    8219        // Note that this doesn't correctly remove ligatures...
    8220        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
    8221    }
    8222
    8223    /**
    8224     * <p>Strips whitespace from the start and end of every String in an array.
    8225     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8226     *
    8227     * <p>A new array is returned each time, except for length zero.
    8228     * A {@code null} array will return {@code null}.
    8229     * An empty array will return itself.
    8230     * A {@code null} array entry will be ignored.</p>
    8231     *
    8232     * <pre>
    8233     * StringUtils.stripAll(null)             = null
    8234     * StringUtils.stripAll([])               = []
    8235     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    8236     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    8237     * </pre>
    8238     *
    8239     * @param strs  the array to remove whitespace from, may be null
    8240     * @return the stripped Strings, {@code null} if null array input
    8241     */
    8242    public static String[] stripAll(final String... strs) {
    8243        return stripAll(strs, null);
    8244    }
    8245
    8246    /**
    8247     * <p>Strips any of a set of characters from the start and end of every
    8248     * String in an array.</p>
    8249     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8250     *
    8251     * <p>A new array is returned each time, except for length zero.
    8252     * A {@code null} array will return {@code null}.
    8253     * An empty array will return itself.
    8254     * A {@code null} array entry will be ignored.
    8255     * A {@code null} stripChars will strip whitespace as defined by
    8256     * {@link Character#isWhitespace(char)}.</p>
    8257     *
    8258     * <pre>
    8259     * StringUtils.stripAll(null, *)                = null
    8260     * StringUtils.stripAll([], *)                  = []
    8261     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    8262     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    8263     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    8264     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    8265     * </pre>
    8266     *
    8267     * @param strs  the array to remove characters from, may be null
    8268     * @param stripChars  the characters to remove, null treated as whitespace
    8269     * @return the stripped Strings, {@code null} if null array input
    8270     */
    8271    public static String[] stripAll(final String[] strs, final String stripChars) {
    8272        final int strsLen = ArrayUtils.getLength(strs);
    8273        if (strsLen == 0) {
    8274            return strs;
    8275        }
    8276        final String[] newArr = new String[strsLen];
    8277        for (int i = 0; i < strsLen; i++) {
    8278            newArr[i] = strip(strs[i], stripChars);
    8279        }
    8280        return newArr;
    8281    }
    8282
    8283    /**
    8284     * <p>Strips any of a set of characters from the end of a String.</p>
    8285     *
    8286     * <p>A {@code null} input String returns {@code null}.
    8287     * An empty string ("") input returns the empty string.</p>
    8288     *
    8289     * <p>If the stripChars String is {@code null}, whitespace is
    8290     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8291     *
    8292     * <pre>
    8293     * StringUtils.stripEnd(null, *)          = null
    8294     * StringUtils.stripEnd("", *)            = ""
    8295     * StringUtils.stripEnd("abc", "")        = "abc"
    8296     * StringUtils.stripEnd("abc", null)      = "abc"
    8297     * StringUtils.stripEnd("  abc", null)    = "  abc"
    8298     * StringUtils.stripEnd("abc  ", null)    = "abc"
    8299     * StringUtils.stripEnd(" abc ", null)    = " abc"
    8300     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    8301     * StringUtils.stripEnd("120.00", ".0")   = "12"
    8302     * </pre>
    8303     *
    8304     * @param str  the String to remove characters from, may be null
    8305     * @param stripChars  the set of characters to remove, null treated as whitespace
    8306     * @return the stripped String, {@code null} if null String input
    8307     */
    8308    public static String stripEnd(final String str, final String stripChars) {
    8309        int end = length(str);
    8310        if (end == 0) {
    8311            return str;
    8312        }
    8313
    8314        if (stripChars == null) {
    8315            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
    8316                end--;
    8317            }
    8318        } else if (stripChars.isEmpty()) {
    8319            return str;
    8320        } else {
    8321            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
    8322                end--;
    8323            }
    8324        }
    8325        return str.substring(0, end);
    8326    }
    8327
    8328    /**
    8329     * <p>Strips any of a set of characters from the start of a String.</p>
    8330     *
    8331     * <p>A {@code null} input String returns {@code null}.
    8332     * An empty string ("") input returns the empty string.</p>
    8333     *
    8334     * <p>If the stripChars String is {@code null}, whitespace is
    8335     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8336     *
    8337     * <pre>
    8338     * StringUtils.stripStart(null, *)          = null
    8339     * StringUtils.stripStart("", *)            = ""
    8340     * StringUtils.stripStart("abc", "")        = "abc"
    8341     * StringUtils.stripStart("abc", null)      = "abc"
    8342     * StringUtils.stripStart("  abc", null)    = "abc"
    8343     * StringUtils.stripStart("abc  ", null)    = "abc  "
    8344     * StringUtils.stripStart(" abc ", null)    = "abc "
    8345     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    8346     * </pre>
    8347     *
    8348     * @param str  the String to remove characters from, may be null
    8349     * @param stripChars  the characters to remove, null treated as whitespace
    8350     * @return the stripped String, {@code null} if null String input
    8351     */
    8352    public static String stripStart(final String str, final String stripChars) {
    8353        final int strLen = length(str);
    8354        if (strLen == 0) {
    8355            return str;
    8356        }
    8357        int start = 0;
    8358        if (stripChars == null) {
    8359            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
    8360                start++;
    8361            }
    8362        } else if (stripChars.isEmpty()) {
    8363            return str;
    8364        } else {
    8365            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
    8366                start++;
    8367            }
    8368        }
    8369        return str.substring(start);
    8370    }
    8371
    8372    /**
    8373     * <p>Strips whitespace from the start and end of a String  returning
    8374     * an empty String if {@code null} input.</p>
    8375     *
    8376     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
    8377     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8378     *
    8379     * <pre>
    8380     * StringUtils.stripToEmpty(null)     = ""
    8381     * StringUtils.stripToEmpty("")       = ""
    8382     * StringUtils.stripToEmpty("   ")    = ""
    8383     * StringUtils.stripToEmpty("abc")    = "abc"
    8384     * StringUtils.stripToEmpty("  abc")  = "abc"
    8385     * StringUtils.stripToEmpty("abc  ")  = "abc"
    8386     * StringUtils.stripToEmpty(" abc ")  = "abc"
    8387     * StringUtils.stripToEmpty(" ab c ") = "ab c"
    8388     * </pre>
    8389     *
    8390     * @param str  the String to be stripped, may be null
    8391     * @return the trimmed String, or an empty String if {@code null} input
    8392     * @since 2.0
    8393     */
    8394    public static String stripToEmpty(final String str) {
    8395        return str == null ? EMPTY : strip(str, null);
    8396    }
    8397
    8398    /**
    8399     * <p>Strips whitespace from the start and end of a String  returning
    8400     * {@code null} if the String is empty ("") after the strip.</p>
    8401     *
    8402     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
    8403     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8404     *
    8405     * <pre>
    8406     * StringUtils.stripToNull(null)     = null
    8407     * StringUtils.stripToNull("")       = null
    8408     * StringUtils.stripToNull("   ")    = null
    8409     * StringUtils.stripToNull("abc")    = "abc"
    8410     * StringUtils.stripToNull("  abc")  = "abc"
    8411     * StringUtils.stripToNull("abc  ")  = "abc"
    8412     * StringUtils.stripToNull(" abc ")  = "abc"
    8413     * StringUtils.stripToNull(" ab c ") = "ab c"
    8414     * </pre>
    8415     *
    8416     * @param str  the String to be stripped, may be null
    8417     * @return the stripped String,
    8418     *  {@code null} if whitespace, empty or null String input
    8419     * @since 2.0
    8420     */
    8421    public static String stripToNull(String str) {
    8422        if (str == null) {
    8423            return null;
    8424        }
    8425        str = strip(str, null);
    8426        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
    8427    }
    8428
    8429    /**
    8430     * <p>Gets a substring from the specified String avoiding exceptions.</p>
    8431     *
    8432     * <p>A negative start position can be used to start {@code n}
    8433     * characters from the end of the String.</p>
    8434     *
    8435     * <p>A {@code null} String will return {@code null}.
    8436     * An empty ("") String will return "".</p>
    8437     *
    8438     * <pre>
    8439     * StringUtils.substring(null, *)   = null
    8440     * StringUtils.substring("", *)     = ""
    8441     * StringUtils.substring("abc", 0)  = "abc"
    8442     * StringUtils.substring("abc", 2)  = "c"
    8443     * StringUtils.substring("abc", 4)  = ""
    8444     * StringUtils.substring("abc", -2) = "bc"
    8445     * StringUtils.substring("abc", -4) = "abc"
    8446     * </pre>
    8447     *
    8448     * @param str  the String to get the substring from, may be null
    8449     * @param start  the position to start from, negative means
    8450     *  count back from the end of the String by this many characters
    8451     * @return substring from start position, {@code null} if null String input
    8452     */
    8453    public static String substring(final String str, int start) {
    8454        if (str == null) {
    8455            return null;
    8456        }
    8457
    8458        // handle negatives, which means last n characters
    8459        if (start < 0) {
    8460            start = str.length() + start; // remember start is negative
    8461        }
    8462
    8463        if (start < 0) {
    8464            start = 0;
    8465        }
    8466        if (start > str.length()) {
    8467            return EMPTY;
    8468        }
    8469
    8470        return str.substring(start);
    8471    }
    8472
    8473    /**
    8474     * <p>Gets a substring from the specified String avoiding exceptions.</p>
    8475     *
    8476     * <p>A negative start position can be used to start/end {@code n}
    8477     * characters from the end of the String.</p>
    8478     *
    8479     * <p>The returned substring starts with the character in the {@code start}
    8480     * position and ends before the {@code end} position. All position counting is
    8481     * zero-based -- i.e., to start at the beginning of the string use
    8482     * {@code start = 0}. Negative start and end positions can be used to
    8483     * specify offsets relative to the end of the String.</p>
    8484     *
    8485     * <p>If {@code start} is not strictly to the left of {@code end}, ""
    8486     * is returned.</p>
    8487     *
    8488     * <pre>
    8489     * StringUtils.substring(null, *, *)    = null
    8490     * StringUtils.substring("", * ,  *)    = "";
    8491     * StringUtils.substring("abc", 0, 2)   = "ab"
    8492     * StringUtils.substring("abc", 2, 0)   = ""
    8493     * StringUtils.substring("abc", 2, 4)   = "c"
    8494     * StringUtils.substring("abc", 4, 6)   = ""
    8495     * StringUtils.substring("abc", 2, 2)   = ""
    8496     * StringUtils.substring("abc", -2, -1) = "b"
    8497     * StringUtils.substring("abc", -4, 2)  = "ab"
    8498     * </pre>
    8499     *
    8500     * @param str  the String to get the substring from, may be null
    8501     * @param start  the position to start from, negative means
    8502     *  count back from the end of the String by this many characters
    8503     * @param end  the position to end at (exclusive), negative means
    8504     *  count back from the end of the String by this many characters
    8505     * @return substring from start position to end position,
    8506     *  {@code null} if null String input
    8507     */
    8508    public static String substring(final String str, int start, int end) {
    8509        if (str == null) {
    8510            return null;
    8511        }
    8512
    8513        // handle negatives
    8514        if (end < 0) {
    8515            end = str.length() + end; // remember end is negative
    8516        }
    8517        if (start < 0) {
    8518            start = str.length() + start; // remember start is negative
    8519        }
    8520
    8521        // check length next
    8522        if (end > str.length()) {
    8523            end = str.length();
    8524        }
    8525
    8526        // if start is greater than end, return ""
    8527        if (start > end) {
    8528            return EMPTY;
    8529        }
    8530
    8531        if (start < 0) {
    8532            start = 0;
    8533        }
    8534        if (end < 0) {
    8535            end = 0;
    8536        }
    8537
    8538        return str.substring(start, end);
    8539    }
    8540
    8541    /**
    8542     * <p>Gets the substring after the first occurrence of a separator.
    8543     * The separator is not returned.</p>
    8544     *
    8545     * <p>A {@code null} string input will return {@code null}.
    8546     * An empty ("") string input will return the empty string.
    8547     *
    8548     * <p>If nothing is found, the empty string is returned.</p>
    8549     *
    8550     * <pre>
    8551     * StringUtils.substringAfter(null, *)      = null
    8552     * StringUtils.substringAfter("", *)        = ""
    8553     * StringUtils.substringAfter("abc", 'a')   = "bc"
    8554     * StringUtils.substringAfter("abcba", 'b') = "cba"
    8555     * StringUtils.substringAfter("abc", 'c')   = ""
    8556     * StringUtils.substringAfter("abc", 'd')   = ""
    8557     * StringUtils.substringAfter(" abc", 32)   = "abc"
    8558     * </pre>
    8559     *
    8560     * @param str  the String to get a substring from, may be null
    8561     * @param separator  the character to search.
    8562     * @return the substring after the first occurrence of the separator,
    8563     *  {@code null} if null String input
    8564     * @since 3.11
    8565     */
    8566    public static String substringAfter(final String str, final int separator) {
    8567        if (isEmpty(str)) {
    8568            return str;
    8569        }
    8570        final int pos = str.indexOf(separator);
    8571        if (pos == INDEX_NOT_FOUND) {
    8572            return EMPTY;
    8573        }
    8574        return str.substring(pos + 1);
    8575    }
    8576
    8577    /**
    8578     * <p>Gets the substring after the first occurrence of a separator.
    8579     * The separator is not returned.</p>
    8580     *
    8581     * <p>A {@code null} string input will return {@code null}.
    8582     * An empty ("") string input will return the empty string.
    8583     * A {@code null} separator will return the empty string if the
    8584     * input string is not {@code null}.</p>
    8585     *
    8586     * <p>If nothing is found, the empty string is returned.</p>
    8587     *
    8588     * <pre>
    8589     * StringUtils.substringAfter(null, *)      = null
    8590     * StringUtils.substringAfter("", *)        = ""
    8591     * StringUtils.substringAfter(*, null)      = ""
    8592     * StringUtils.substringAfter("abc", "a")   = "bc"
    8593     * StringUtils.substringAfter("abcba", "b") = "cba"
    8594     * StringUtils.substringAfter("abc", "c")   = ""
    8595     * StringUtils.substringAfter("abc", "d")   = ""
    8596     * StringUtils.substringAfter("abc", "")    = "abc"
    8597     * </pre>
    8598     *
    8599     * @param str  the String to get a substring from, may be null
    8600     * @param separator  the String to search for, may be null
    8601     * @return the substring after the first occurrence of the separator,
    8602     *  {@code null} if null String input
    8603     * @since 2.0
    8604     */
    8605    public static String substringAfter(final String str, final String separator) {
    8606        if (isEmpty(str)) {
    8607            return str;
    8608        }
    8609        if (separator == null) {
    8610            return EMPTY;
    8611        }
    8612        final int pos = str.indexOf(separator);
    8613        if (pos == INDEX_NOT_FOUND) {
    8614            return EMPTY;
    8615        }
    8616        return str.substring(pos + separator.length());
    8617    }
    8618
    8619    /**
    8620     * <p>Gets the substring after the last occurrence of a separator.
    8621     * The separator is not returned.</p>
    8622     *
    8623     * <p>A {@code null} string input will return {@code null}.
    8624     * An empty ("") string input will return the empty string.
    8625     *
    8626     * <p>If nothing is found, the empty string is returned.</p>
    8627     *
    8628     * <pre>
    8629     * StringUtils.substringAfterLast(null, *)      = null
    8630     * StringUtils.substringAfterLast("", *)        = ""
    8631     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
    8632     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
    8633     * StringUtils.substringAfterLast("abcba", 'b') = "a"
    8634     * StringUtils.substringAfterLast("abc", 'c')   = ""
    8635     * StringUtils.substringAfterLast("a", 'a')     = ""
    8636     * StringUtils.substringAfterLast("a", 'z')     = ""
    8637     * </pre>
    8638     *
    8639     * @param str  the String to get a substring from, may be null
    8640     * @param separator  the String to search for, may be null
    8641     * @return the substring after the last occurrence of the separator,
    8642     *  {@code null} if null String input
    8643     * @since 3.11
    8644     */
    8645    public static String substringAfterLast(final String str, final int separator) {
    8646        if (isEmpty(str)) {
    8647            return str;
    8648        }
    8649        final int pos = str.lastIndexOf(separator);
    8650        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
    8651            return EMPTY;
    8652        }
    8653        return str.substring(pos + 1);
    8654    }
    8655
    8656    /**
    8657     * <p>Gets the substring after the last occurrence of a separator.
    8658     * The separator is not returned.</p>
    8659     *
    8660     * <p>A {@code null} string input will return {@code null}.
    8661     * An empty ("") string input will return the empty string.
    8662     * An empty or {@code null} separator will return the empty string if
    8663     * the input string is not {@code null}.</p>
    8664     *
    8665     * <p>If nothing is found, the empty string is returned.</p>
    8666     *
    8667     * <pre>
    8668     * StringUtils.substringAfterLast(null, *)      = null
    8669     * StringUtils.substringAfterLast("", *)        = ""
    8670     * StringUtils.substringAfterLast(*, "")        = ""
    8671     * StringUtils.substringAfterLast(*, null)      = ""
    8672     * StringUtils.substringAfterLast("abc", "a")   = "bc"
    8673     * StringUtils.substringAfterLast("abcba", "b") = "a"
    8674     * StringUtils.substringAfterLast("abc", "c")   = ""
    8675     * StringUtils.substringAfterLast("a", "a")     = ""
    8676     * StringUtils.substringAfterLast("a", "z")     = ""
    8677     * </pre>
    8678     *
    8679     * @param str  the String to get a substring from, may be null
    8680     * @param separator  the String to search for, may be null
    8681     * @return the substring after the last occurrence of the separator,
    8682     *  {@code null} if null String input
    8683     * @since 2.0
    8684     */
    8685    public static String substringAfterLast(final String str, final String separator) {
    8686        if (isEmpty(str)) {
    8687            return str;
    8688        }
    8689        if (isEmpty(separator)) {
    8690            return EMPTY;
    8691        }
    8692        final int pos = str.lastIndexOf(separator);
    8693        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
    8694            return EMPTY;
    8695        }
    8696        return str.substring(pos + separator.length());
    8697    }
    8698
    8699    /**
    8700     * <p>
    8701     * Gets the substring before the first occurrence of a separator. The separator is not returned.
    8702     * </p>
    8703     *
    8704     * <p>
    8705     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8706     * </p>
    8707     *
    8708     * <p>
    8709     * If nothing is found, the string input is returned.
    8710     * </p>
    8711     *
    8712     * <pre>
    8713     * StringUtils.substringBefore(null, *)      = null
    8714     * StringUtils.substringBefore("", *)        = ""
    8715     * StringUtils.substringBefore("abc", 'a')   = ""
    8716     * StringUtils.substringBefore("abcba", 'b') = "a"
    8717     * StringUtils.substringBefore("abc", 'c')   = "ab"
    8718     * StringUtils.substringBefore("abc", 'd')   = "abc"
    8719     * </pre>
    8720     *
    8721     * @param str the String to get a substring from, may be null
    8722     * @param separator the String to search for, may be null
    8723     * @return the substring before the first occurrence of the separator, {@code null} if null String input
    8724     * @since 3.12.0
    8725     */
    8726    public static String substringBefore(final String str, final int separator) {
    8727        if (isEmpty(str)) {
    8728            return str;
    8729        }
    8730        final int pos = str.indexOf(separator);
    8731        if (pos == INDEX_NOT_FOUND) {
    8732            return str;
    8733        }
    8734        return str.substring(0, pos);
    8735    }
    8736
    8737    /**
    8738     * <p>Gets the substring before the first occurrence of a separator.
    8739     * The separator is not returned.</p>
    8740     *
    8741     * <p>A {@code null} string input will return {@code null}.
    8742     * An empty ("") string input will return the empty string.
    8743     * A {@code null} separator will return the input string.</p>
    8744     *
    8745     * <p>If nothing is found, the string input is returned.</p>
    8746     *
    8747     * <pre>
    8748     * StringUtils.substringBefore(null, *)      = null
    8749     * StringUtils.substringBefore("", *)        = ""
    8750     * StringUtils.substringBefore("abc", "a")   = ""
    8751     * StringUtils.substringBefore("abcba", "b") = "a"
    8752     * StringUtils.substringBefore("abc", "c")   = "ab"
    8753     * StringUtils.substringBefore("abc", "d")   = "abc"
    8754     * StringUtils.substringBefore("abc", "")    = ""
    8755     * StringUtils.substringBefore("abc", null)  = "abc"
    8756     * </pre>
    8757     *
    8758     * @param str  the String to get a substring from, may be null
    8759     * @param separator  the String to search for, may be null
    8760     * @return the substring before the first occurrence of the separator,
    8761     *  {@code null} if null String input
    8762     * @since 2.0
    8763     */
    8764    public static String substringBefore(final String str, final String separator) {
    8765        if (isEmpty(str) || separator == null) {
    8766            return str;
    8767        }
    8768        if (separator.isEmpty()) {
    8769            return EMPTY;
    8770        }
    8771        final int pos = str.indexOf(separator);
    8772        if (pos == INDEX_NOT_FOUND) {
    8773            return str;
    8774        }
    8775        return str.substring(0, pos);
    8776    }
    8777
    8778    /**
    8779     * <p>Gets the substring before the last occurrence of a separator.
    8780     * The separator is not returned.</p>
    8781     *
    8782     * <p>A {@code null} string input will return {@code null}.
    8783     * An empty ("") string input will return the empty string.
    8784     * An empty or {@code null} separator will return the input string.</p>
    8785     *
    8786     * <p>If nothing is found, the string input is returned.</p>
    8787     *
    8788     * <pre>
    8789     * StringUtils.substringBeforeLast(null, *)      = null
    8790     * StringUtils.substringBeforeLast("", *)        = ""
    8791     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    8792     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    8793     * StringUtils.substringBeforeLast("a", "a")     = ""
    8794     * StringUtils.substringBeforeLast("a", "z")     = "a"
    8795     * StringUtils.substringBeforeLast("a", null)    = "a"
    8796     * StringUtils.substringBeforeLast("a", "")      = "a"
    8797     * </pre>
    8798     *
    8799     * @param str  the String to get a substring from, may be null
    8800     * @param separator  the String to search for, may be null
    8801     * @return the substring before the last occurrence of the separator,
    8802     *  {@code null} if null String input
    8803     * @since 2.0
    8804     */
    8805    public static String substringBeforeLast(final String str, final String separator) {
    8806        if (isEmpty(str) || isEmpty(separator)) {
    8807            return str;
    8808        }
    8809        final int pos = str.lastIndexOf(separator);
    8810        if (pos == INDEX_NOT_FOUND) {
    8811            return str;
    8812        }
    8813        return str.substring(0, pos);
    8814    }
    8815
    8816    /**
    8817     * <p>Gets the String that is nested in between two instances of the
    8818     * same String.</p>
    8819     *
    8820     * <p>A {@code null} input String returns {@code null}.
    8821     * A {@code null} tag returns {@code null}.</p>
    8822     *
    8823     * <pre>
    8824     * StringUtils.substringBetween(null, *)            = null
    8825     * StringUtils.substringBetween("", "")             = ""
    8826     * StringUtils.substringBetween("", "tag")          = null
    8827     * StringUtils.substringBetween("tagabctag", null)  = null
    8828     * StringUtils.substringBetween("tagabctag", "")    = ""
    8829     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    8830     * </pre>
    8831     *
    8832     * @param str  the String containing the substring, may be null
    8833     * @param tag  the String before and after the substring, may be null
    8834     * @return the substring, {@code null} if no match
    8835     * @since 2.0
    8836     */
    8837    public static String substringBetween(final String str, final String tag) {
    8838        return substringBetween(str, tag, tag);
    8839    }
    8840
    8841    /**
    8842     * <p>Gets the String that is nested in between two Strings.
    8843     * Only the first match is returned.</p>
    8844     *
    8845     * <p>A {@code null} input String returns {@code null}.
    8846     * A {@code null} open/close returns {@code null} (no match).
    8847     * An empty ("") open and close returns an empty string.</p>
    8848     *
    8849     * <pre>
    8850     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    8851     * StringUtils.substringBetween(null, *, *)          = null
    8852     * StringUtils.substringBetween(*, null, *)          = null
    8853     * StringUtils.substringBetween(*, *, null)          = null
    8854     * StringUtils.substringBetween("", "", "")          = ""
    8855     * StringUtils.substringBetween("", "", "]")         = null
    8856     * StringUtils.substringBetween("", "[", "]")        = null
    8857     * StringUtils.substringBetween("yabcz", "", "")     = ""
    8858     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    8859     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    8860     * </pre>
    8861     *
    8862     * @param str  the String containing the substring, may be null
    8863     * @param open  the String before the substring, may be null
    8864     * @param close  the String after the substring, may be null
    8865     * @return the substring, {@code null} if no match
    8866     * @since 2.0
    8867     */
    8868    public static String substringBetween(final String str, final String open, final String close) {
    8869        if (!ObjectUtils.allNotNull(str, open, close)) {
    8870            return null;
    8871        }
    8872        final int start = str.indexOf(open);
    8873        if (start != INDEX_NOT_FOUND) {
    8874            final int end = str.indexOf(close, start + open.length());
    8875            if (end != INDEX_NOT_FOUND) {
    8876                return str.substring(start + open.length(), end);
    8877            }
    8878        }
    8879        return null;
    8880    }
    8881
    8882    /**
    8883     * <p>Searches a String for substrings delimited by a start and end tag,
    8884     * returning all matching substrings in an array.</p>
    8885     *
    8886     * <p>A {@code null} input String returns {@code null}.
    8887     * A {@code null} open/close returns {@code null} (no match).
    8888     * An empty ("") open/close returns {@code null} (no match).</p>
    8889     *
    8890     * <pre>
    8891     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    8892     * StringUtils.substringsBetween(null, *, *)            = null
    8893     * StringUtils.substringsBetween(*, null, *)            = null
    8894     * StringUtils.substringsBetween(*, *, null)            = null
    8895     * StringUtils.substringsBetween("", "[", "]")          = []
    8896     * </pre>
    8897     *
    8898     * @param str  the String containing the substrings, null returns null, empty returns empty
    8899     * @param open  the String identifying the start of the substring, empty returns null
    8900     * @param close  the String identifying the end of the substring, empty returns null
    8901     * @return a String Array of substrings, or {@code null} if no match
    8902     * @since 2.3
    8903     */
    8904    public static String[] substringsBetween(final String str, final String open, final String close) {
    8905        if (str == null || isEmpty(open) || isEmpty(close)) {
    8906            return null;
    8907        }
    8908        final int strLen = str.length();
    8909        if (strLen == 0) {
    8910            return ArrayUtils.EMPTY_STRING_ARRAY;
    8911        }
    8912        final int closeLen = close.length();
    8913        final int openLen = open.length();
    8914        final List<String> list = new ArrayList<>();
    8915        int pos = 0;
    8916        while (pos < strLen - closeLen) {
    8917            int start = str.indexOf(open, pos);
    8918            if (start < 0) {
    8919                break;
    8920            }
    8921            start += openLen;
    8922            final int end = str.indexOf(close, start);
    8923            if (end < 0) {
    8924                break;
    8925            }
    8926            list.add(str.substring(start, end));
    8927            pos = end + closeLen;
    8928        }
    8929        if (list.isEmpty()) {
    8930            return null;
    8931        }
    8932        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    8933    }
    8934
    8935    /**
    8936     * <p>Swaps the case of a String changing upper and title case to
    8937     * lower case, and lower case to upper case.</p>
    8938     *
    8939     * <ul>
    8940     *  <li>Upper case character converts to Lower case</li>
    8941     *  <li>Title case character converts to Lower case</li>
    8942     *  <li>Lower case character converts to Upper case</li>
    8943     * </ul>
    8944     *
    8945     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
    8946     * A {@code null} input String returns {@code null}.</p>
    8947     *
    8948     * <pre>
    8949     * StringUtils.swapCase(null)                 = null
    8950     * StringUtils.swapCase("")                   = ""
    8951     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    8952     * </pre>
    8953     *
    8954     * <p>NOTE: This method changed in Lang version 2.0.
    8955     * It no longer performs a word based algorithm.
    8956     * If you only use ASCII, you will notice no change.
    8957     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
    8958     *
    8959     * @param str  the String to swap case, may be null
    8960     * @return the changed String, {@code null} if null String input
    8961     */
    8962    public static String swapCase(final String str) {
    8963        if (isEmpty(str)) {
    8964            return str;
    8965        }
    8966
    8967        final int strLen = str.length();
    8968        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    8969        int outOffset = 0;
    8970        for (int i = 0; i < strLen; ) {
    8971            final int oldCodepoint = str.codePointAt(i);
    8972            final int newCodePoint;
    8973            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
    8974                newCodePoint = Character.toLowerCase(oldCodepoint);
    8975            } else if (Character.isLowerCase(oldCodepoint)) {
    8976                newCodePoint = Character.toUpperCase(oldCodepoint);
    8977            } else {
    8978                newCodePoint = oldCodepoint;
    8979            }
    8980            newCodePoints[outOffset++] = newCodePoint;
    8981            i += Character.charCount(newCodePoint);
    8982         }
    8983        return new String(newCodePoints, 0, outOffset);
    8984    }
    8985
    8986    /**
    8987     * <p>Converts a {@code CharSequence} into an array of code points.</p>
    8988     *
    8989     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
    8990     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
    8991     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
    8992     *
    8993     * <pre>
    8994     * StringUtils.toCodePoints(null)   =  null
    8995     * StringUtils.toCodePoints("")     =  []  // empty array
    8996     * </pre>
    8997     *
    8998     * @param cs the character sequence to convert
    8999     * @return an array of code points
    9000     * @since 3.6
    9001     */
    9002    public static int[] toCodePoints(final CharSequence cs) {
    9003        if (cs == null) {
    9004            return null;
    9005        }
    9006        if (cs.length() == 0) {
    9007            return ArrayUtils.EMPTY_INT_ARRAY;
    9008        }
    9009
    9010        final String s = cs.toString();
    9011        final int[] result = new int[s.codePointCount(0, s.length())];
    9012        int index = 0;
    9013        for (int i = 0; i < result.length; i++) {
    9014            result[i] = s.codePointAt(index);
    9015            index += Character.charCount(result[i]);
    9016        }
    9017        return result;
    9018    }
    9019
    9020    /**
    9021     * Converts a {@code byte[]} to a String using the specified character encoding.
    9022     *
    9023     * @param bytes
    9024     *            the byte array to read from
    9025     * @param charset
    9026     *            the encoding to use, if null then use the platform default
    9027     * @return a new String
    9028     * @throws NullPointerException
    9029     *             if {@code bytes} is null
    9030     * @since 3.2
    9031     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
    9032     */
    9033    public static String toEncodedString(final byte[] bytes, final Charset charset) {
    9034        return new String(bytes, Charsets.toCharset(charset));
    9035    }
    9036
    9037    /**
    9038     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
    9039     *
    9040     * @param source A source String or null.
    9041     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
    9042     * @since 3.10
    9043     */
    9044    public static String toRootLowerCase(final String source) {
    9045        return source == null ? null : source.toLowerCase(Locale.ROOT);
    9046    }
    9047
    9048    /**
    9049     * Converts the given source String as a upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
    9050     *
    9051     * @param source A source String or null.
    9052     * @return the given source String as a upper-case using the {@link Locale#ROOT} locale or null.
    9053     * @since 3.10
    9054     */
    9055    public static String toRootUpperCase(final String source) {
    9056        return source == null ? null : source.toUpperCase(Locale.ROOT);
    9057    }
    9058
    9059    /**
    9060     * Converts a {@code byte[]} to a String using the specified character encoding.
    9061     *
    9062     * @param bytes
    9063     *            the byte array to read from
    9064     * @param charsetName
    9065     *            the encoding to use, if null then use the platform default
    9066     * @return a new String
    9067     * @throws UnsupportedEncodingException
    9068     *             If the named charset is not supported
    9069     * @throws NullPointerException
    9070     *             if the input is null
    9071     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
    9072     * @since 3.1
    9073     */
    9074    @Deprecated
    9075    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
    9076        return new String(bytes, Charsets.toCharset(charsetName));
    9077    }
    9078
    9079    private static String toStringOrEmpty(final Object obj) {
    9080        return Objects.toString(obj, EMPTY);
    9081    }
    9082
    9083    /**
    9084     * <p>Removes control characters (char &lt;= 32) from both
    9085     * ends of this String, handling {@code null} by returning
    9086     * {@code null}.</p>
    9087     *
    9088     * <p>The String is trimmed using {@link String#trim()}.
    9089     * Trim removes start and end characters &lt;= 32.
    9090     * To strip whitespace use {@link #strip(String)}.</p>
    9091     *
    9092     * <p>To trim your choice of characters, use the
    9093     * {@link #strip(String, String)} methods.</p>
    9094     *
    9095     * <pre>
    9096     * StringUtils.trim(null)          = null
    9097     * StringUtils.trim("")            = ""
    9098     * StringUtils.trim("     ")       = ""
    9099     * StringUtils.trim("abc")         = "abc"
    9100     * StringUtils.trim("    abc    ") = "abc"
    9101     * </pre>
    9102     *
    9103     * @param str  the String to be trimmed, may be null
    9104     * @return the trimmed string, {@code null} if null String input
    9105     */
    9106    public static String trim(final String str) {
    9107        return str == null ? null : str.trim();
    9108    }
    9109
    9110    /**
    9111     * <p>Removes control characters (char &lt;= 32) from both
    9112     * ends of this String returning an empty String ("") if the String
    9113     * is empty ("") after the trim or if it is {@code null}.
    9114     *
    9115     * <p>The String is trimmed using {@link String#trim()}.
    9116     * Trim removes start and end characters &lt;= 32.
    9117     * To strip whitespace use {@link #stripToEmpty(String)}.</p>
    9118     *
    9119     * <pre>
    9120     * StringUtils.trimToEmpty(null)          = ""
    9121     * StringUtils.trimToEmpty("")            = ""
    9122     * StringUtils.trimToEmpty("     ")       = ""
    9123     * StringUtils.trimToEmpty("abc")         = "abc"
    9124     * StringUtils.trimToEmpty("    abc    ") = "abc"
    9125     * </pre>
    9126     *
    9127     * @param str  the String to be trimmed, may be null
    9128     * @return the trimmed String, or an empty String if {@code null} input
    9129     * @since 2.0
    9130     */
    9131    public static String trimToEmpty(final String str) {
    9132        return str == null ? EMPTY : str.trim();
    9133    }
    9134
    9135    /**
    9136     * <p>Removes control characters (char &lt;= 32) from both
    9137     * ends of this String returning {@code null} if the String is
    9138     * empty ("") after the trim or if it is {@code null}.
    9139     *
    9140     * <p>The String is trimmed using {@link String#trim()}.
    9141     * Trim removes start and end characters &lt;= 32.
    9142     * To strip whitespace use {@link #stripToNull(String)}.</p>
    9143     *
    9144     * <pre>
    9145     * StringUtils.trimToNull(null)          = null
    9146     * StringUtils.trimToNull("")            = null
    9147     * StringUtils.trimToNull("     ")       = null
    9148     * StringUtils.trimToNull("abc")         = "abc"
    9149     * StringUtils.trimToNull("    abc    ") = "abc"
    9150     * </pre>
    9151     *
    9152     * @param str  the String to be trimmed, may be null
    9153     * @return the trimmed String,
    9154     *  {@code null} if only chars &lt;= 32, empty or null String input
    9155     * @since 2.0
    9156     */
    9157    public static String trimToNull(final String str) {
    9158        final String ts = trim(str);
    9159        return isEmpty(ts) ? null : ts;
    9160    }
    9161
    9162    /**
    9163     * <p>Truncates a String. This will turn
    9164     * "Now is the time for all good men" into "Now is the time for".</p>
    9165     *
    9166     * <p>Specifically:</p>
    9167     * <ul>
    9168     *   <li>If {@code str} is less than {@code maxWidth} characters
    9169     *       long, return it.</li>
    9170     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
    9171     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    9172     *       {@code IllegalArgumentException}.</li>
    9173     *   <li>In no case will it return a String of length greater than
    9174     *       {@code maxWidth}.</li>
    9175     * </ul>
    9176     *
    9177     * <pre>
    9178     * StringUtils.truncate(null, 0)       = null
    9179     * StringUtils.truncate(null, 2)       = null
    9180     * StringUtils.truncate("", 4)         = ""
    9181     * StringUtils.truncate("abcdefg", 4)  = "abcd"
    9182     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
    9183     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
    9184     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
    9185     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
    9186     * </pre>
    9187     *
    9188     * @param str  the String to truncate, may be null
    9189     * @param maxWidth  maximum length of result String, must be positive
    9190     * @return truncated String, {@code null} if null String input
    9191     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
    9192     * @since 3.5
    9193     */
    9194    public static String truncate(final String str, final int maxWidth) {
    9195        return truncate(str, 0, maxWidth);
    9196    }
    9197
    9198    /**
    9199     * <p>Truncates a String. This will turn
    9200     * "Now is the time for all good men" into "is the time for all".</p>
    9201     *
    9202     * <p>Works like {@code truncate(String, int)}, but allows you to specify
    9203     * a "left edge" offset.
    9204     *
    9205     * <p>Specifically:</p>
    9206     * <ul>
    9207     *   <li>If {@code str} is less than {@code maxWidth} characters
    9208     *       long, return it.</li>
    9209     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
    9210     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    9211     *       {@code IllegalArgumentException}.</li>
    9212     *   <li>If {@code offset} is less than {@code 0}, throw an
    9213     *       {@code IllegalArgumentException}.</li>
    9214     *   <li>In no case will it return a String of length greater than
    9215     *       {@code maxWidth}.</li>
    9216     * </ul>
    9217     *
    9218     * <pre>
    9219     * StringUtils.truncate(null, 0, 0) = null
    9220     * StringUtils.truncate(null, 2, 4) = null
    9221     * StringUtils.truncate("", 0, 10) = ""
    9222     * StringUtils.truncate("", 2, 10) = ""
    9223     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
    9224     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
    9225     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
    9226     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
    9227     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
    9228     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
    9229     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
    9230     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
    9231     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
    9232     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
    9233     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
    9234     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
    9235     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
    9236     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
    9237     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
    9238     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
    9239     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
    9240     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
    9241     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
    9242     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
    9243     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
    9244     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
    9245     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
    9246     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
    9247     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
    9248     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
    9249     * </pre>
    9250     *
    9251     * @param str  the String to truncate, may be null
    9252     * @param offset  left edge of source String
    9253     * @param maxWidth  maximum length of result String, must be positive
    9254     * @return truncated String, {@code null} if null String input
    9255     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
    9256     * @since 3.5
    9257     */
    9258    public static String truncate(final String str, final int offset, final int maxWidth) {
    9259        if (offset < 0) {
    9260            throw new IllegalArgumentException("offset cannot be negative");
    9261        }
    9262        if (maxWidth < 0) {
    9263            throw new IllegalArgumentException("maxWith cannot be negative");
    9264        }
    9265        if (str == null) {
    9266            return null;
    9267        }
    9268        if (offset > str.length()) {
    9269            return EMPTY;
    9270        }
    9271        if (str.length() > maxWidth) {
    9272            final int ix = Math.min(offset + maxWidth, str.length());
    9273            return str.substring(offset, ix);
    9274        }
    9275        return str.substring(offset);
    9276    }
    9277
    9278    /**
    9279     * <p>Uncapitalizes a String, changing the first character to lower case as
    9280     * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
    9281     *
    9282     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
    9283     * A {@code null} input String returns {@code null}.</p>
    9284     *
    9285     * <pre>
    9286     * StringUtils.uncapitalize(null)  = null
    9287     * StringUtils.uncapitalize("")    = ""
    9288     * StringUtils.uncapitalize("cat") = "cat"
    9289     * StringUtils.uncapitalize("Cat") = "cat"
    9290     * StringUtils.uncapitalize("CAT") = "cAT"
    9291     * </pre>
    9292     *
    9293     * @param str the String to uncapitalize, may be null
    9294     * @return the uncapitalized String, {@code null} if null String input
    9295     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
    9296     * @see #capitalize(String)
    9297     * @since 2.0
    9298     */
    9299    public static String uncapitalize(final String str) {
    9300        final int strLen = length(str);
    9301        if (strLen == 0) {
    9302            return str;
    9303        }
    9304
    9305        final int firstCodepoint = str.codePointAt(0);
    9306        final int newCodePoint = Character.toLowerCase(firstCodepoint);
    9307        if (firstCodepoint == newCodePoint) {
    9308            // already capitalized
    9309            return str;
    9310        }
    9311
    9312        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    9313        int outOffset = 0;
    9314        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
    9315        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
    9316            final int codepoint = str.codePointAt(inOffset);
    9317            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
    9318            inOffset += Character.charCount(codepoint);
    9319         }
    9320        return new String(newCodePoints, 0, outOffset);
    9321    }
    9322
    9323    /**
    9324     * <p>
    9325     * Unwraps a given string from a character.
    9326     * </p>
    9327     *
    9328     * <pre>
    9329     * StringUtils.unwrap(null, null)         = null
    9330     * StringUtils.unwrap(null, '\0')         = null
    9331     * StringUtils.unwrap(null, '1')          = null
    9332     * StringUtils.unwrap("a", 'a')           = "a"
    9333     * StringUtils.unwrap("aa", 'a')           = ""
    9334     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
    9335     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
    9336     * StringUtils.unwrap("A", '#')           = "A"
    9337     * StringUtils.unwrap("#A", '#')          = "#A"
    9338     * StringUtils.unwrap("A#", '#')          = "A#"
    9339     * </pre>
    9340     *
    9341     * @param str
    9342     *          the String to be unwrapped, can be null
    9343     * @param wrapChar
    9344     *          the character used to unwrap
    9345     * @return unwrapped String or the original string
    9346     *          if it is not quoted properly with the wrapChar
    9347     * @since 3.6
    9348     */
    9349    public static String unwrap(final String str, final char wrapChar) {
    9350        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
    9351            return str;
    9352        }
    9353
    9354        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
    9355            final int startIndex = 0;
    9356            final int endIndex = str.length() - 1;
    9357
    9358            return str.substring(startIndex + 1, endIndex);
    9359        }
    9360
    9361        return str;
    9362    }
    9363
    9364    /**
    9365     * <p>
    9366     * Unwraps a given string from anther string.
    9367     * </p>
    9368     *
    9369     * <pre>
    9370     * StringUtils.unwrap(null, null)         = null
    9371     * StringUtils.unwrap(null, "")           = null
    9372     * StringUtils.unwrap(null, "1")          = null
    9373     * StringUtils.unwrap("a", "a")           = "a"
    9374     * StringUtils.unwrap("aa", "a")          = ""
    9375     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
    9376     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
    9377     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
    9378     * StringUtils.unwrap("A", "#")           = "A"
    9379     * StringUtils.unwrap("#A", "#")          = "#A"
    9380     * StringUtils.unwrap("A#", "#")          = "A#"
    9381     * </pre>
    9382     *
    9383     * @param str
    9384     *          the String to be unwrapped, can be null
    9385     * @param wrapToken
    9386     *          the String used to unwrap
    9387     * @return unwrapped String or the original string
    9388     *          if it is not quoted properly with the wrapToken
    9389     * @since 3.6
    9390     */
    9391    public static String unwrap(final String str, final String wrapToken) {
    9392        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
    9393            return str;
    9394        }
    9395
    9396        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
    9397            final int startIndex = str.indexOf(wrapToken);
    9398            final int endIndex = str.lastIndexOf(wrapToken);
    9399            final int wrapLength = wrapToken.length();
    9400
    9401            if (startIndex != -1 && endIndex != -1) {
    9402                return str.substring(startIndex + wrapLength, endIndex);
    9403            }
    9404        }
    9405
    9406        return str;
    9407    }
    9408
    9409    /**
    9410     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
    9411     *
    9412     * <p>A {@code null} input String returns {@code null}.</p>
    9413     *
    9414     * <pre>
    9415     * StringUtils.upperCase(null)  = null
    9416     * StringUtils.upperCase("")    = ""
    9417     * StringUtils.upperCase("aBc") = "ABC"
    9418     * </pre>
    9419     *
    9420     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
    9421     * the result of this method is affected by the current locale.
    9422     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    9423     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    9424     *
    9425     * @param str  the String to upper case, may be null
    9426     * @return the upper cased String, {@code null} if null String input
    9427     */
    9428    public static String upperCase(final String str) {
    9429        if (str == null) {
    9430            return null;
    9431        }
    9432        return str.toUpperCase();
    9433    }
    9434
    9435    /**
    9436     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
    9437     *
    9438     * <p>A {@code null} input String returns {@code null}.</p>
    9439     *
    9440     * <pre>
    9441     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    9442     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    9443     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    9444     * </pre>
    9445     *
    9446     * @param str  the String to upper case, may be null
    9447     * @param locale  the locale that defines the case transformation rules, must not be null
    9448     * @return the upper cased String, {@code null} if null String input
    9449     * @since 2.5
    9450     */
    9451    public static String upperCase(final String str, final Locale locale) {
    9452        if (str == null) {
    9453            return null;
    9454        }
    9455        return str.toUpperCase(LocaleUtils.toLocale(locale));
    9456    }
    9457
    9458    /**
    9459     * Returns the string representation of the {@code char} array or null.
    9460     *
    9461     * @param value the character array.
    9462     * @return a String or null
    9463     * @see String#valueOf(char[])
    9464     * @since 3.9
    9465     */
    9466    public static String valueOf(final char[] value) {
    9467        return value == null ? null : String.valueOf(value);
    9468    }
    9469
    9470    /**
    9471     * <p>
    9472     * Wraps a string with a char.
    9473     * </p>
    9474     *
    9475     * <pre>
    9476     * StringUtils.wrap(null, *)        = null
    9477     * StringUtils.wrap("", *)          = ""
    9478     * StringUtils.wrap("ab", '\0')     = "ab"
    9479     * StringUtils.wrap("ab", 'x')      = "xabx"
    9480     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9481     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
    9482     * </pre>
    9483     *
    9484     * @param str
    9485     *            the string to be wrapped, may be {@code null}
    9486     * @param wrapWith
    9487     *            the char that will wrap {@code str}
    9488     * @return the wrapped string, or {@code null} if {@code str==null}
    9489     * @since 3.4
    9490     */
    9491    public static String wrap(final String str, final char wrapWith) {
    9492
    9493        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9494            return str;
    9495        }
    9496
    9497        return wrapWith + str + wrapWith;
    9498    }
    9499
    9500    /**
    9501     * <p>
    9502     * Wraps a String with another String.
    9503     * </p>
    9504     *
    9505     * <p>
    9506     * A {@code null} input String returns {@code null}.
    9507     * </p>
    9508     *
    9509     * <pre>
    9510     * StringUtils.wrap(null, *)         = null
    9511     * StringUtils.wrap("", *)           = ""
    9512     * StringUtils.wrap("ab", null)      = "ab"
    9513     * StringUtils.wrap("ab", "x")       = "xabx"
    9514     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9515     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
    9516     * StringUtils.wrap("ab", "'")       = "'ab'"
    9517     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
    9518     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9519     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9520     * </pre>
    9521     *
    9522     * @param str
    9523     *            the String to be wrapper, may be null
    9524     * @param wrapWith
    9525     *            the String that will wrap str
    9526     * @return wrapped String, {@code null} if null String input
    9527     * @since 3.4
    9528     */
    9529    public static String wrap(final String str, final String wrapWith) {
    9530
    9531        if (isEmpty(str) || isEmpty(wrapWith)) {
    9532            return str;
    9533        }
    9534
    9535        return wrapWith.concat(str).concat(wrapWith);
    9536    }
    9537
    9538    /**
    9539     * <p>
    9540     * Wraps a string with a char if that char is missing from the start or end of the given string.
    9541     * </p>
    9542     *
    9543     * <p>A new {@code String} will not be created if {@code str} is already wrapped.</p>
    9544     *
    9545     * <pre>
    9546     * StringUtils.wrapIfMissing(null, *)        = null
    9547     * StringUtils.wrapIfMissing("", *)          = ""
    9548     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
    9549     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
    9550     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
    9551     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
    9552     * StringUtils.wrapIfMissing("/", '/')  = "/"
    9553     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
    9554     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
    9555     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
    9556     * </pre>
    9557     *
    9558     * @param str
    9559     *            the string to be wrapped, may be {@code null}
    9560     * @param wrapWith
    9561     *            the char that will wrap {@code str}
    9562     * @return the wrapped string, or {@code null} if {@code str==null}
    9563     * @since 3.5
    9564     */
    9565    public static String wrapIfMissing(final String str, final char wrapWith) {
    9566        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9567            return str;
    9568        }
    9569        final boolean wrapStart = str.charAt(0) != wrapWith;
    9570        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
    9571        if (!wrapStart && !wrapEnd) {
    9572            return str;
    9573        }
    9574
    9575        final StringBuilder builder = new StringBuilder(str.length() + 2);
    9576        if (wrapStart) {
    9577            builder.append(wrapWith);
    9578        }
    9579        builder.append(str);
    9580        if (wrapEnd) {
    9581            builder.append(wrapWith);
    9582        }
    9583        return builder.toString();
    9584    }
    9585
    9586    /**
    9587     * <p>
    9588     * Wraps a string with a string if that string is missing from the start or end of the given string.
    9589     * </p>
    9590     *
    9591     * <p>A new {@code String} will not be created if {@code str} is already wrapped.</p>
    9592     *
    9593     * <pre>
    9594     * StringUtils.wrapIfMissing(null, *)         = null
    9595     * StringUtils.wrapIfMissing("", *)           = ""
    9596     * StringUtils.wrapIfMissing("ab", null)      = "ab"
    9597     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
    9598     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
    9599     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
    9600     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
    9601     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
    9602     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
    9603     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
    9604     * StringUtils.wrapIfMissing("/", "/")  = "/"
    9605     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
    9606     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
    9607     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
    9608     * </pre>
    9609     *
    9610     * @param str
    9611     *            the string to be wrapped, may be {@code null}
    9612     * @param wrapWith
    9613     *            the string that will wrap {@code str}
    9614     * @return the wrapped string, or {@code null} if {@code str==null}
    9615     * @since 3.5
    9616     */
    9617    public static String wrapIfMissing(final String str, final String wrapWith) {
    9618        if (isEmpty(str) || isEmpty(wrapWith)) {
    9619            return str;
    9620        }
    9621
    9622        final boolean wrapStart = !str.startsWith(wrapWith);
    9623        final boolean wrapEnd = !str.endsWith(wrapWith);
    9624        if (!wrapStart && !wrapEnd) {
    9625            return str;
    9626        }
    9627
    9628        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
    9629        if (wrapStart) {
    9630            builder.append(wrapWith);
    9631        }
    9632        builder.append(str);
    9633        if (wrapEnd) {
    9634            builder.append(wrapWith);
    9635        }
    9636        return builder.toString();
    9637    }
    9638
    9639    /**
    9640     * <p>{@code StringUtils} instances should NOT be constructed in
    9641     * standard programming. Instead, the class should be used as
    9642     * {@code StringUtils.trim(" foo ");}.</p>
    9643     *
    9644     * <p>This constructor is public to permit tools that require a JavaBean
    9645     * instance to operate.</p>
    9646     */
    9647    public StringUtils() {
    9648    }
    9649
    9650}