    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.io.UnsupportedEncodingException;
    020import java.nio.charset.Charset;
    021import java.text.Normalizer;
    022import java.util.ArrayList;
    023import java.util.Arrays;
    024import java.util.HashSet;
    025import java.util.Iterator;
    026import java.util.List;
    027import java.util.Locale;
    028import java.util.Objects;
    029import java.util.Set;
    030import java.util.function.Supplier;
    031import java.util.regex.Pattern;
    032
    033import org.apache.commons.lang3.function.Suppliers;
    034import org.apache.commons.lang3.function.ToBooleanBiFunction;
    035import org.apache.commons.lang3.stream.LangCollectors;
    036import org.apache.commons.lang3.stream.Streams;
    037
    038/**
    039 * Operations on {@link String} that are
    040 * {@code null} safe.
    041 *
    042 * <ul>
    043 *  <li><b>IsEmpty/IsBlank</b>
    044 *      - checks if a String contains text</li>
    045 *  <li><b>Trim/Strip</b>
    046 *      - removes leading and trailing whitespace</li>
    047 *  <li><b>Equals/Compare</b>
    048 *      - compares two strings in a null-safe manner</li>
    049 *  <li><b>startsWith</b>
    050 *      - check if a String starts with a prefix in a null-safe manner</li>
    051 *  <li><b>endsWith</b>
    052 *      - check if a String ends with a suffix in a null-safe manner</li>
    053 *  <li><b>IndexOf/LastIndexOf/Contains</b>
    054 *      - null-safe index-of checks
    055 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
    056 *      - index-of any of a set of Strings</li>
    057 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
    058 *      - checks if String contains only/none/any of these characters</li>
    059 *  <li><b>Substring/Left/Right/Mid</b>
    060 *      - null-safe substring extractions</li>
    061 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
    062 *      - substring extraction relative to other strings</li>
    063 *  <li><b>Split/Join</b>
    064 *      - splits a String into an array of substrings and vice versa</li>
    065 *  <li><b>Remove/Delete</b>
    066 *      - removes part of a String</li>
    067 *  <li><b>Replace/Overlay</b>
    068 *      - Searches a String and replaces one String with another</li>
    069 *  <li><b>Chomp/Chop</b>
    070 *      - removes the last part of a String</li>
    071 *  <li><b>AppendIfMissing</b>
    072 *      - appends a suffix to the end of the String if not present</li>
    073 *  <li><b>PrependIfMissing</b>
    074 *      - prepends a prefix to the start of the String if not present</li>
    075 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
    076 *      - pads a String</li>
    077 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
    078 *      - changes the case of a String</li>
    079 *  <li><b>CountMatches</b>
    080 *      - counts the number of occurrences of one String in another</li>
    081 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
    082 *      - checks the characters in a String</li>
    083 *  <li><b>DefaultString</b>
    084 *      - protects against a null input String</li>
    085 *  <li><b>Rotate</b>
    086 *      - rotate (circular shift) a String</li>
    087 *  <li><b>Reverse/ReverseDelimited</b>
    088 *      - reverses a String</li>
    089 *  <li><b>Abbreviate</b>
    090 *      - abbreviates a string using ellipses or another given String</li>
    091 *  <li><b>Difference</b>
    092 *      - compares Strings and reports on their differences</li>
    093 *  <li><b>LevenshteinDistance</b>
    094 *      - the number of changes needed to change one String into another</li>
    095 * </ul>
    096 *
    097 * <p>The {@link StringUtils} class defines certain words related to
    098 * String handling.</p>
    099 *
    100 * <ul>
    101 *  <li>null - {@code null}</li>
    102 *  <li>empty - a zero-length string ({@code ""})</li>
    103 *  <li>space - the space character ({@code ' '}, char 32)</li>
    104 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
    105 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
    106 * </ul>
    107 *
    108 * <p>{@link StringUtils} handles {@code null} input Strings quietly.
    109 * That is to say that a {@code null} input will return {@code null}.
    110 * Where a {@code boolean} or {@code int} is being returned
    111 * details vary by method.</p>
    112 *
    113 * <p>A side effect of the {@code null} handling is that a
    114 * {@link NullPointerException} should be considered a bug in
    115 * {@link StringUtils}.</p>
    116 *
    117 * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
    118 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
    119 *
    120 * <p>#ThreadSafe#</p>
    121 * @see String
    122 * @since 1.0
    123 */
    124//@Immutable
    125public class StringUtils {
    126
    127    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
    128    // Whitespace:
    129    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
    130    // where WHITESPACE is a string of all whitespace characters
    131    //
    132    // Character access:
    133    // String.charAt(n) versus toCharArray(), then array[n]
    134    // String.charAt(n) is about 15% worse for a 10K string
    135    // They are about equal for a length 50 string
    136    // String.charAt(n) is about 4 times better for a length 3 string
    137    // String.charAt(n) is best bet overall
    138    //
    139    // Append:
    140    // String.concat about twice as fast as StringBuffer.append
    141    // (not sure who tested this)
    142
    143    /**
    144     * A String for a space character.
    145     *
    146     * @since 3.2
    147     */
    148    public static final String SPACE = " ";
    149
    150    /**
    151     * The empty String {@code ""}.
    152     * @since 2.0
    153     */
    154    public static final String EMPTY = "";
    155
    156    /**
    157     * A String for linefeed LF ("\n").
    158     *
    159     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    160     *      for Character and String Literals</a>
    161     * @since 3.2
    162     */
    163    public static final String LF = "\n";
    164
    165    /**
    166     * A String for carriage return CR ("\r").
    167     *
    168     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    169     *      for Character and String Literals</a>
    170     * @since 3.2
    171     */
    172    public static final String CR = "\r";
    173
    174    /**
    175     * Represents a failed index search.
    176     * @since 2.1
    177     */
    178    public static final int INDEX_NOT_FOUND = -1;
    179
    180    /**
    181     * The maximum size to which the padding constant(s) can expand.
    182     */
    183    private static final int PAD_LIMIT = 8192;
    184
    185    /**
    186     * Pattern used in {@link #stripAccents(String)}.
    187     */
    188    private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
    189
    190    /**
    191     * Abbreviates a String using ellipses. This will turn
    192     * "Now is the time for all good men" into "Now is the time for..."
    193     *
    194     * <p>Specifically:</p>
    195     * <ul>
    196     *   <li>If the number of characters in {@code str} is less than or equal to
    197     *       {@code maxWidth}, return {@code str}.</li>
    198     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
    199     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
    200     *       {@link IllegalArgumentException}.</li>
    201     *   <li>In no case will it return a String of length greater than
    202     *       {@code maxWidth}.</li>
    203     * </ul>
    204     *
    205     * <pre>
    206     * StringUtils.abbreviate(null, *)      = null
    207     * StringUtils.abbreviate("", 4)        = ""
    208     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
    209     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
    210     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
    211     * StringUtils.abbreviate("abcdefg", 4) = "a..."
    212     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
    213     * </pre>
    214     *
    215     * @param str  the String to check, may be null
    216     * @param maxWidth  maximum length of result String, must be at least 4
    217     * @return abbreviated String, {@code null} if null String input
    218     * @throws IllegalArgumentException if the width is too small
    219     * @since 2.0
    220     */
    221    public static String abbreviate(final String str, final int maxWidth) {
    222        return abbreviate(str, "...", 0, maxWidth);
    223    }
    224
    225    /**
    226     * Abbreviates a String using ellipses. This will turn
    227     * "Now is the time for all good men" into "...is the time for..."
    228     *
    229     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
    230     * a "left edge" offset.  Note that this left edge is not necessarily going to
    231     * be the leftmost character in the result, or the first character following the
    232     * ellipses, but it will appear somewhere in the result.
    233     *
    234     * <p>In no case will it return a String of length greater than
    235     * {@code maxWidth}.</p>
    236     *
    237     * <pre>
    238     * StringUtils.abbreviate(null, *, *)                = null
    239     * StringUtils.abbreviate("", 0, 4)                  = ""
    240     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
    241     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
    242     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
    243     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
    244     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
    245     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
    246     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
    247     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
    248     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
    249     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
    250     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
    251     * </pre>
    252     *
    253     * @param str  the String to check, may be null
    254     * @param offset  left edge of source String
    255     * @param maxWidth  maximum length of result String, must be at least 4
    256     * @return abbreviated String, {@code null} if null String input
    257     * @throws IllegalArgumentException if the width is too small
    258     * @since 2.0
    259     */
    260    public static String abbreviate(final String str, final int offset, final int maxWidth) {
    261        return abbreviate(str, "...", offset, maxWidth);
    262    }
    263
    264    /**
    265     * Abbreviates a String using another given String as replacement marker. This will turn
    266     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
    267     * as the replacement marker.
    268     *
    269     * <p>Specifically:</p>
    270     * <ul>
    271     *   <li>If the number of characters in {@code str} is less than or equal to
    272     *       {@code maxWidth}, return {@code str}.</li>
    273     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
    274     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
    275     *       {@link IllegalArgumentException}.</li>
    276     *   <li>In no case will it return a String of length greater than
    277     *       {@code maxWidth}.</li>
    278     * </ul>
    279     *
    280     * <pre>
    281     * StringUtils.abbreviate(null, "...", *)      = null
    282     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
    283     * StringUtils.abbreviate("", "...", 4)        = ""
    284     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
    285     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
    286     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
    287     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
    288     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
    289     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
    290     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
    291     * </pre>
    292     *
    293     * @param str  the String to check, may be null
    294     * @param abbrevMarker  the String used as replacement marker
    295     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
    296     * @return abbreviated String, {@code null} if null String input
    297     * @throws IllegalArgumentException if the width is too small
    298     * @since 3.6
    299     */
    300    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
    301        return abbreviate(str, abbrevMarker, 0, maxWidth);
    302    }
    303    /**
    304     * Abbreviates a String using a given replacement marker. This will turn
    305     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
    306     * as the replacement marker.
    307     *
    308     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
    309     * a "left edge" offset.  Note that this left edge is not necessarily going to
    310     * be the leftmost character in the result, or the first character following the
    311     * replacement marker, but it will appear somewhere in the result.
    312     *
    313     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
    314     *
    315     * <pre>
    316     * StringUtils.abbreviate(null, null, *, *)                 = null
    317     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
    318     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
    319     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
    320     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
    321     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
    322     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
    323     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
    324     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
    325     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
    326     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
    327     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
    328     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
    329     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
    330     * </pre>
    331     *
    332     * @param str  the String to check, may be null
    333     * @param abbrevMarker  the String used as replacement marker
    334     * @param offset  left edge of source String
    335     * @param maxWidth  maximum length of result String, must be at least 4
    336     * @return abbreviated String, {@code null} if null String input
    337     * @throws IllegalArgumentException if the width is too small
    338     * @since 3.6
    339     */
    340    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
    341        if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
    342            return substring(str, 0, maxWidth);
    343        }
    344        if (isAnyEmpty(str, abbrevMarker)) {
    345            return str;
    346        }
    347        final int abbrevMarkerLength = abbrevMarker.length();
    348        final int minAbbrevWidth = abbrevMarkerLength + 1;
    349        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
    350
    351        if (maxWidth < minAbbrevWidth) {
    352            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
    353        }
    354        final int strLen = str.length();
    355        if (strLen <= maxWidth) {
    356            return str;
    357        }
    358        if (offset > strLen) {
    359            offset = strLen;
    360        }
    361        if (strLen - offset < maxWidth - abbrevMarkerLength) {
    362            offset = strLen - (maxWidth - abbrevMarkerLength);
    363        }
    364        if (offset <= abbrevMarkerLength + 1) {
    365            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
    366        }
    367        if (maxWidth < minAbbrevWidthOffset) {
    368            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
    369        }
    370        if (offset + maxWidth - abbrevMarkerLength < strLen) {
    371            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
    372        }
    373        return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
    374    }
    375
    376    /**
    377     * Abbreviates a String to the length passed, replacing the middle characters with the supplied
    378     * replacement String.
    379     *
    380     * <p>This abbreviation only occurs if the following criteria is met:</p>
    381     * <ul>
    382     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
    383     * <li>The length to truncate to is less than the length of the supplied String</li>
    384     * <li>The length to truncate to is greater than 0</li>
    385     * <li>The abbreviated String will have enough room for the length supplied replacement String
    386     * and the first and last characters of the supplied String for abbreviation</li>
    387     * </ul>
    388     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
    389     * </p>
    390     *
    391     * <pre>
    392     * StringUtils.abbreviateMiddle(null, null, 0)    = null
    393     * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
    394     * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
    395     * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
    396     * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
    397     * </pre>
    398     *
    399     * @param str  the String to abbreviate, may be null
    400     * @param middle the String to replace the middle characters with, may be null
    401     * @param length the length to abbreviate {@code str} to.
    402     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
    403     * @since 2.5
    404     */
    405    public static String abbreviateMiddle(final String str, final String middle, final int length) {
    406        if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
    407            return str;
    408        }
    409        final int targetSting = length - middle.length();
    410        final int startOffset = targetSting / 2 + targetSting % 2;
    411        final int endOffset = str.length() - targetSting / 2;
    412        return str.substring(0, startOffset) + middle + str.substring(endOffset);
    413    }
    414
    415    /**
    416     * Appends the suffix to the end of the string if the string does not
    417     * already end with the suffix.
    418     *
    419     * @param str The string.
    420     * @param suffix The suffix to append to the end of the string.
    421     * @param ignoreCase Indicates whether the compare should ignore case.
    422     * @param suffixes Additional suffixes that are valid terminators (optional).
    423     *
    424     * @return A new String if suffix was appended, the same string otherwise.
    425     */
    426    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
    427        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
    428            return str;
    429        }
    430        if (ArrayUtils.isNotEmpty(suffixes)) {
    431            for (final CharSequence s : suffixes) {
    432                if (endsWith(str, s, ignoreCase)) {
    433                    return str;
    434                }
    435            }
    436        }
    437        return str + suffix;
    438    }
    439
    440    /**
    441     * Appends the suffix to the end of the string if the string does not
    442     * already end with any of the suffixes.
    443     *
    444     * <pre>
    445     * StringUtils.appendIfMissing(null, null)      = null
    446     * StringUtils.appendIfMissing("abc", null)     = "abc"
    447     * StringUtils.appendIfMissing("", "xyz"        = "xyz"
    448     * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
    449     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
    450     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
    451     * </pre>
    452     * <p>With additional suffixes,</p>
    453     * <pre>
    454     * StringUtils.appendIfMissing(null, null, null)       = null
    455     * StringUtils.appendIfMissing("abc", null, null)      = "abc"
    456     * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
    457     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    458     * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
    459     * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
    460     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
    461     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
    462     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
    463     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
    464     * </pre>
    465     *
    466     * @param str The string.
    467     * @param suffix The suffix to append to the end of the string.
    468     * @param suffixes Additional suffixes that are valid terminators.
    469     *
    470     * @return A new String if suffix was appended, the same string otherwise.
    471     *
    472     * @since 3.2
    473     */
    474    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    475        return appendIfMissing(str, suffix, false, suffixes);
    476    }
    477
    478    /**
    479     * Appends the suffix to the end of the string if the string does not
    480     * already end, case-insensitive, with any of the suffixes.
    481     *
    482     * <pre>
    483     * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
    484     * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
    485     * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
    486     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
    487     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
    488     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
    489     * </pre>
    490     * <p>With additional suffixes,</p>
    491     * <pre>
    492     * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
    493     * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
    494     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
    495     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    496     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
    497     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
    498     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
    499     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
    500     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
    501     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
    502     * </pre>
    503     *
    504     * @param str The string.
    505     * @param suffix The suffix to append to the end of the string.
    506     * @param suffixes Additional suffixes that are valid terminators.
    507     *
    508     * @return A new String if suffix was appended, the same string otherwise.
    509     *
    510     * @since 3.2
    511     */
    512    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    513        return appendIfMissing(str, suffix, true, suffixes);
    514    }
    515
    516    /**
    517     * Capitalizes a String changing the first character to title case as
    518     * per {@link Character#toTitleCase(int)}. No other characters are changed.
    519     *
    520     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
    521     * A {@code null} input String returns {@code null}.</p>
    522     *
    523     * <pre>
    524     * StringUtils.capitalize(null)    = null
    525     * StringUtils.capitalize("")      = ""
    526     * StringUtils.capitalize("cat")   = "Cat"
    527     * StringUtils.capitalize("cAt")   = "CAt"
    528     * StringUtils.capitalize("'cat'") = "'cat'"
    529     * </pre>
    530     *
    531     * @param str the String to capitalize, may be null
    532     * @return the capitalized String, {@code null} if null String input
    533     * @see org.apache.commons.text.WordUtils#capitalize(String)
    534     * @see #uncapitalize(String)
    535     * @since 2.0
    536     */
    537    public static String capitalize(final String str) {
    538        final int strLen = length(str);
    539        if (strLen == 0) {
    540            return str;
    541        }
    542
    543        final int firstCodepoint = str.codePointAt(0);
    544        final int newCodePoint = Character.toTitleCase(firstCodepoint);
    545        if (firstCodepoint == newCodePoint) {
    546            // already capitalized
    547            return str;
    548        }
    549
    550        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    551        int outOffset = 0;
    552        newCodePoints[outOffset++] = newCodePoint; // copy the first code point
    553        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
    554            final int codePoint = str.codePointAt(inOffset);
    555            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
    556            inOffset += Character.charCount(codePoint);
    557         }
    558        return new String(newCodePoints, 0, outOffset);
    559    }
    560
    561    /**
    562     * Centers a String in a larger String of size {@code size}
    563     * using the space character (' ').
    564     *
    565     * <p>If the size is less than the String length, the original String is returned.
    566     * A {@code null} String returns {@code null}.
    567     * A negative size is treated as zero.</p>
    568     *
    569     * <p>Equivalent to {@code center(str, size, " ")}.</p>
    570     *
    571     * <pre>
    572     * StringUtils.center(null, *)   = null
    573     * StringUtils.center("", 4)     = "    "
    574     * StringUtils.center("ab", -1)  = "ab"
    575     * StringUtils.center("ab", 4)   = " ab "
    576     * StringUtils.center("abcd", 2) = "abcd"
    577     * StringUtils.center("a", 4)    = " a  "
    578     * </pre>
    579     *
    580     * @param str  the String to center, may be null
    581     * @param size  the int size of new String, negative treated as zero
    582     * @return centered String, {@code null} if null String input
    583     */
    584    public static String center(final String str, final int size) {
    585        return center(str, size, ' ');
    586    }
    587
    588    /**
    589     * Centers a String in a larger String of size {@code size}.
    590     * Uses a supplied character as the value to pad the String with.
    591     *
    592     * <p>If the size is less than the String length, the String is returned.
    593     * A {@code null} String returns {@code null}.
    594     * A negative size is treated as zero.</p>
    595     *
    596     * <pre>
    597     * StringUtils.center(null, *, *)     = null
    598     * StringUtils.center("", 4, ' ')     = "    "
    599     * StringUtils.center("ab", -1, ' ')  = "ab"
    600     * StringUtils.center("ab", 4, ' ')   = " ab "
    601     * StringUtils.center("abcd", 2, ' ') = "abcd"
    602     * StringUtils.center("a", 4, ' ')    = " a  "
    603     * StringUtils.center("a", 4, 'y')    = "yayy"
    604     * </pre>
    605     *
    606     * @param str  the String to center, may be null
    607     * @param size  the int size of new String, negative treated as zero
    608     * @param padChar  the character to pad the new String with
    609     * @return centered String, {@code null} if null String input
    610     * @since 2.0
    611     */
    612    public static String center(String str, final int size, final char padChar) {
    613        if (str == null || size <= 0) {
    614            return str;
    615        }
    616        final int strLen = str.length();
    617        final int pads = size - strLen;
    618        if (pads <= 0) {
    619            return str;
    620        }
    621        str = leftPad(str, strLen + pads / 2, padChar);
    622        return rightPad(str, size, padChar);
    623    }
    624
    625    /**
    626     * Centers a String in a larger String of size {@code size}.
    627     * Uses a supplied String as the value to pad the String with.
    628     *
    629     * <p>If the size is less than the String length, the String is returned.
    630     * A {@code null} String returns {@code null}.
    631     * A negative size is treated as zero.</p>
    632     *
    633     * <pre>
    634     * StringUtils.center(null, *, *)     = null
    635     * StringUtils.center("", 4, " ")     = "    "
    636     * StringUtils.center("ab", -1, " ")  = "ab"
    637     * StringUtils.center("ab", 4, " ")   = " ab "
    638     * StringUtils.center("abcd", 2, " ") = "abcd"
    639     * StringUtils.center("a", 4, " ")    = " a  "
    640     * StringUtils.center("a", 4, "yz")   = "yayz"
    641     * StringUtils.center("abc", 7, null) = "  abc  "
    642     * StringUtils.center("abc", 7, "")   = "  abc  "
    643     * </pre>
    644     *
    645     * @param str  the String to center, may be null
    646     * @param size  the int size of new String, negative treated as zero
    647     * @param padStr  the String to pad the new String with, must not be null or empty
    648     * @return centered String, {@code null} if null String input
    649     * @throws IllegalArgumentException if padStr is {@code null} or empty
    650     */
    651    public static String center(String str, final int size, String padStr) {
    652        if (str == null || size <= 0) {
    653            return str;
    654        }
    655        if (isEmpty(padStr)) {
    656            padStr = SPACE;
    657        }
    658        final int strLen = str.length();
    659        final int pads = size - strLen;
    660        if (pads <= 0) {
    661            return str;
    662        }
    663        str = leftPad(str, strLen + pads / 2, padStr);
    664        return rightPad(str, size, padStr);
    665    }
    666
    667    /**
    668     * Removes one newline from end of a String if it's there,
    669     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
    670     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
    671     *
    672     * <p>NOTE: This method changed in 2.0.
    673     * It now more closely matches Perl chomp.</p>
    674     *
    675     * <pre>
    676     * StringUtils.chomp(null)          = null
    677     * StringUtils.chomp("")            = ""
    678     * StringUtils.chomp("abc \r")      = "abc "
    679     * StringUtils.chomp("abc\n")       = "abc"
    680     * StringUtils.chomp("abc\r\n")     = "abc"
    681     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
    682     * StringUtils.chomp("abc\n\r")     = "abc\n"
    683     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
    684     * StringUtils.chomp("\r")          = ""
    685     * StringUtils.chomp("\n")          = ""
    686     * StringUtils.chomp("\r\n")        = ""
    687     * </pre>
    688     *
    689     * @param str  the String to chomp a newline from, may be null
    690     * @return String without newline, {@code null} if null String input
    691     */
    692    public static String chomp(final String str) {
    693        if (isEmpty(str)) {
    694            return str;
    695        }
    696
    697        if (str.length() == 1) {
    698            final char ch = str.charAt(0);
    699            if (ch == CharUtils.CR || ch == CharUtils.LF) {
    700                return EMPTY;
    701            }
    702            return str;
    703        }
    704
    705        int lastIdx = str.length() - 1;
    706        final char last = str.charAt(lastIdx);
    707
    708        if (last == CharUtils.LF) {
    709            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    710                lastIdx--;
    711            }
    712        } else if (last != CharUtils.CR) {
    713            lastIdx++;
    714        }
    715        return str.substring(0, lastIdx);
    716    }
    717
    718    /**
    719     * Removes {@code separator} from the end of
    720     * {@code str} if it's there, otherwise leave it alone.
    721     *
    722     * <p>NOTE: This method changed in version 2.0.
    723     * It now more closely matches Perl chomp.
    724     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
    725     * This method uses {@link String#endsWith(String)}.</p>
    726     *
    727     * <pre>
    728     * StringUtils.chomp(null, *)         = null
    729     * StringUtils.chomp("", *)           = ""
    730     * StringUtils.chomp("foobar", "bar") = "foo"
    731     * StringUtils.chomp("foobar", "baz") = "foobar"
    732     * StringUtils.chomp("foo", "foo")    = ""
    733     * StringUtils.chomp("foo ", "foo")   = "foo "
    734     * StringUtils.chomp(" foo", "foo")   = " "
    735     * StringUtils.chomp("foo", "foooo")  = "foo"
    736     * StringUtils.chomp("foo", "")       = "foo"
    737     * StringUtils.chomp("foo", null)     = "foo"
    738     * </pre>
    739     *
    740     * @param str  the String to chomp from, may be null
    741     * @param separator  separator String, may be null
    742     * @return String without trailing separator, {@code null} if null String input
    743     * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
    744     */
    745    @Deprecated
    746    public static String chomp(final String str, final String separator) {
    747        return removeEnd(str, separator);
    748    }
    749
    750    /**
    751     * Remove the last character from a String.
    752     *
    753     * <p>If the String ends in {@code \r\n}, then remove both
    754     * of them.</p>
    755     *
    756     * <pre>
    757     * StringUtils.chop(null)          = null
    758     * StringUtils.chop("")            = ""
    759     * StringUtils.chop("abc \r")      = "abc "
    760     * StringUtils.chop("abc\n")       = "abc"
    761     * StringUtils.chop("abc\r\n")     = "abc"
    762     * StringUtils.chop("abc")         = "ab"
    763     * StringUtils.chop("abc\nabc")    = "abc\nab"
    764     * StringUtils.chop("a")           = ""
    765     * StringUtils.chop("\r")          = ""
    766     * StringUtils.chop("\n")          = ""
    767     * StringUtils.chop("\r\n")        = ""
    768     * </pre>
    769     *
    770     * @param str  the String to chop last character from, may be null
    771     * @return String without last character, {@code null} if null String input
    772     */
    773    public static String chop(final String str) {
    774        if (str == null) {
    775            return null;
    776        }
    777        final int strLen = str.length();
    778        if (strLen < 2) {
    779            return EMPTY;
    780        }
    781        final int lastIdx = strLen - 1;
    782        final String ret = str.substring(0, lastIdx);
    783        final char last = str.charAt(lastIdx);
    784        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
    785            return ret.substring(0, lastIdx - 1);
    786        }
    787        return ret;
    788    }
    789
    790    /**
    791     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    792     * <ul>
    793     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    794     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    795     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    796     * </ul>
    797     *
    798     * <p>This is a {@code null} safe version of :</p>
    799     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    800     *
    801     * <p>{@code null} value is considered less than non-{@code null} value.
    802     * Two {@code null} references are considered equal.</p>
    803     *
    804     * <pre>
    805     * StringUtils.compare(null, null)   = 0
    806     * StringUtils.compare(null , "a")   &lt; 0
    807     * StringUtils.compare("a", null)    &gt; 0
    808     * StringUtils.compare("abc", "abc") = 0
    809     * StringUtils.compare("a", "b")     &lt; 0
    810     * StringUtils.compare("b", "a")     &gt; 0
    811     * StringUtils.compare("a", "B")     &gt; 0
    812     * StringUtils.compare("ab", "abc")  &lt; 0
    813     * </pre>
    814     *
    815     * @see #compare(String, String, boolean)
    816     * @see String#compareTo(String)
    817     * @param str1  the String to compare from
    818     * @param str2  the String to compare to
    819     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
    820     * @since 3.5
    821     */
    822    public static int compare(final String str1, final String str2) {
    823        return compare(str1, str2, true);
    824    }
    825
    826    /**
    827     * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
    828     * <ul>
    829     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    830     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    831     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    832     * </ul>
    833     *
    834     * <p>This is a {@code null} safe version of :</p>
    835     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    836     *
    837     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    838     * Two {@code null} references are considered equal.</p>
    839     *
    840     * <pre>
    841     * StringUtils.compare(null, null, *)     = 0
    842     * StringUtils.compare(null , "a", true)  &lt; 0
    843     * StringUtils.compare(null , "a", false) &gt; 0
    844     * StringUtils.compare("a", null, true)   &gt; 0
    845     * StringUtils.compare("a", null, false)  &lt; 0
    846     * StringUtils.compare("abc", "abc", *)   = 0
    847     * StringUtils.compare("a", "b", *)       &lt; 0
    848     * StringUtils.compare("b", "a", *)       &gt; 0
    849     * StringUtils.compare("a", "B", *)       &gt; 0
    850     * StringUtils.compare("ab", "abc", *)    &lt; 0
    851     * </pre>
    852     *
    853     * @see String#compareTo(String)
    854     * @param str1  the String to compare from
    855     * @param str2  the String to compare to
    856     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    857     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
    858     * @since 3.5
    859     */
    860    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
    861        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    862            return 0;
    863        }
    864        if (str1 == null) {
    865            return nullIsLess ? -1 : 1;
    866        }
    867        if (str2 == null) {
    868            return nullIsLess ? 1 : - 1;
    869        }
    870        return str1.compareTo(str2);
    871    }
    872
    873    /**
    874     * Compare two Strings lexicographically, ignoring case differences,
    875     * as per {@link String#compareToIgnoreCase(String)}, returning :
    876     * <ul>
    877     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    878     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    879     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    880     * </ul>
    881     *
    882     * <p>This is a {@code null} safe version of :</p>
    883     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    884     *
    885     * <p>{@code null} value is considered less than non-{@code null} value.
    886     * Two {@code null} references are considered equal.
    887     * Comparison is case insensitive.</p>
    888     *
    889     * <pre>
    890     * StringUtils.compareIgnoreCase(null, null)   = 0
    891     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
    892     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
    893     * StringUtils.compareIgnoreCase("abc", "abc") = 0
    894     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
    895     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
    896     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
    897     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
    898     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
    899     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
    900     * </pre>
    901     *
    902     * @see #compareIgnoreCase(String, String, boolean)
    903     * @see String#compareToIgnoreCase(String)
    904     * @param str1  the String to compare from
    905     * @param str2  the String to compare to
    906     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    907     *          ignoring case differences.
    908     * @since 3.5
    909     */
    910    public static int compareIgnoreCase(final String str1, final String str2) {
    911        return compareIgnoreCase(str1, str2, true);
    912    }
    913
    914    /**
    915     * Compare two Strings lexicographically, ignoring case differences,
    916     * as per {@link String#compareToIgnoreCase(String)}, returning :
    917     * <ul>
    918     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    919     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    920     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    921     * </ul>
    922     *
    923     * <p>This is a {@code null} safe version of :</p>
    924     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    925     *
    926     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    927     * Two {@code null} references are considered equal.
    928     * Comparison is case insensitive.</p>
    929     *
    930     * <pre>
    931     * StringUtils.compareIgnoreCase(null, null, *)     = 0
    932     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
    933     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
    934     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
    935     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
    936     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
    937     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
    938     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
    939     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
    940     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
    941     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
    942     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
    943     * </pre>
    944     *
    945     * @see String#compareToIgnoreCase(String)
    946     * @param str1  the String to compare from
    947     * @param str2  the String to compare to
    948     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    949     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    950     *          ignoring case differences.
    951     * @since 3.5
    952     */
    953    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
    954        if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
    955            return 0;
    956        }
    957        if (str1 == null) {
    958            return nullIsLess ? -1 : 1;
    959        }
    960        if (str2 == null) {
    961            return nullIsLess ? 1 : - 1;
    962        }
    963        return str1.compareToIgnoreCase(str2);
    964    }
    965
    966    /**
    967     * Checks if CharSequence contains a search CharSequence, handling {@code null}.
    968     * This method uses {@link String#indexOf(String)} if possible.
    969     *
    970     * <p>A {@code null} CharSequence will return {@code false}.</p>
    971     *
    972     * <pre>
    973     * StringUtils.contains(null, *)     = false
    974     * StringUtils.contains(*, null)     = false
    975     * StringUtils.contains("", "")      = true
    976     * StringUtils.contains("abc", "")   = true
    977     * StringUtils.contains("abc", "a")  = true
    978     * StringUtils.contains("abc", "z")  = false
    979     * </pre>
    980     *
    981     * @param seq  the CharSequence to check, may be null
    982     * @param searchSeq  the CharSequence to find, may be null
    983     * @return true if the CharSequence contains the search CharSequence,
    984     *  false if not or {@code null} string input
    985     * @since 2.0
    986     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
    987     */
    988    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
    989        if (seq == null || searchSeq == null) {
    990            return false;
    991        }
    992        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
    993    }
    994
    995    /**
    996     * Checks if CharSequence contains a search character, handling {@code null}.
    997     * This method uses {@link String#indexOf(int)} if possible.
    998     *
    999     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
    1000     *
    1001     * <pre>
    1002     * StringUtils.contains(null, *)    = false
    1003     * StringUtils.contains("", *)      = false
    1004     * StringUtils.contains("abc", 'a') = true
    1005     * StringUtils.contains("abc", 'z') = false
    1006     * </pre>
    1007     *
    1008     * @param seq  the CharSequence to check, may be null
    1009     * @param searchChar  the character to find
    1010     * @return true if the CharSequence contains the search character,
    1011     *  false if not or {@code null} string input
    1012     * @since 2.0
    1013     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
    1014     */
    1015    public static boolean contains(final CharSequence seq, final int searchChar) {
    1016        if (isEmpty(seq)) {
    1017            return false;
    1018        }
    1019        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
    1020    }
    1021
    1022    /**
    1023     * Checks if the CharSequence contains any character in the given
    1024     * set of characters.
    1025     *
    1026     * <p>A {@code null} CharSequence will return {@code false}.
    1027     * A {@code null} or zero length search array will return {@code false}.</p>
    1028     *
    1029     * <pre>
    1030     * StringUtils.containsAny(null, *)                  = false
    1031     * StringUtils.containsAny("", *)                    = false
    1032     * StringUtils.containsAny(*, null)                  = false
    1033     * StringUtils.containsAny(*, [])                    = false
    1034     * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    1035     * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    1036     * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    1037     * StringUtils.containsAny("aba", ['z'])             = false
    1038     * </pre>
    1039     *
    1040     * @param cs  the CharSequence to check, may be null
    1041     * @param searchChars  the chars to search for, may be null
    1042     * @return the {@code true} if any of the chars are found,
    1043     * {@code false} if no match or null input
    1044     * @since 2.4
    1045     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
    1046     */
    1047    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    1048        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1049            return false;
    1050        }
    1051        final int csLength = cs.length();
    1052        final int searchLength = searchChars.length;
    1053        final int csLast = csLength - 1;
    1054        final int searchLast = searchLength - 1;
    1055        for (int i = 0; i < csLength; i++) {
    1056            final char ch = cs.charAt(i);
    1057            for (int j = 0; j < searchLength; j++) {
    1058                if (searchChars[j] == ch) {
    1059                    if (!Character.isHighSurrogate(ch)) {
    1060                        // ch is in the Basic Multilingual Plane
    1061                        return true;
    1062                    }
    1063                    if (j == searchLast) {
    1064                        // missing low surrogate, fine, like String.indexOf(String)
    1065                        return true;
    1066                    }
    1067                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1068                        return true;
    1069                    }
    1070                }
    1071            }
    1072        }
    1073        return false;
    1074    }
    1075
    1076    /**
    1077     * Checks if the CharSequence contains any character in the given set of characters.
    1078     *
    1079     * <p>
    1080     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
    1081     * {@code false}.
    1082     * </p>
    1083     *
    1084     * <pre>
    1085     * StringUtils.containsAny(null, *)               = false
    1086     * StringUtils.containsAny("", *)                 = false
    1087     * StringUtils.containsAny(*, null)               = false
    1088     * StringUtils.containsAny(*, "")                 = false
    1089     * StringUtils.containsAny("zzabyycdxx", "za")    = true
    1090     * StringUtils.containsAny("zzabyycdxx", "by")    = true
    1091     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
    1092     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
    1093     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
    1094     * StringUtils.containsAny("aba", "z")            = false
    1095     * </pre>
    1096     *
    1097     * @param cs
    1098     *            the CharSequence to check, may be null
    1099     * @param searchChars
    1100     *            the chars to search for, may be null
    1101     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
    1102     * @since 2.4
    1103     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
    1104     */
    1105    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
    1106        if (searchChars == null) {
    1107            return false;
    1108        }
    1109        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
    1110    }
    1111
    1112    /**
    1113     * Checks if the CharSequence contains any of the CharSequences in the given array.
    1114     *
    1115     * <p>
    1116     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1117     * return {@code false}.
    1118     * </p>
    1119     *
    1120     * <pre>
    1121     * StringUtils.containsAny(null, *)            = false
    1122     * StringUtils.containsAny("", *)              = false
    1123     * StringUtils.containsAny(*, null)            = false
    1124     * StringUtils.containsAny(*, [])              = false
    1125     * StringUtils.containsAny("abcd", "ab", null) = true
    1126     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1127     * StringUtils.containsAny("abc", "d", "abc")  = true
    1128     * </pre>
    1129     *
    1130     * @param cs The CharSequence to check, may be null
    1131     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1132     *        null as well.
    1133     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1134     * @since 3.4
    1135     */
    1136    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
    1137        return containsAny(StringUtils::contains, cs, searchCharSequences);
    1138    }
    1139
    1140    /**
    1141     * Checks if the CharSequence contains any of the CharSequences in the given array.
    1142     *
    1143     * <p>
    1144     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1145     * return {@code false}.
    1146     * </p>
    1147     *
    1148     * @param cs The CharSequence to check, may be null
    1149     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1150     *        null as well.
    1151     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1152     * @since 3.12.0
    1153     */
    1154    private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
    1155        final CharSequence cs, final CharSequence... searchCharSequences) {
    1156        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
    1157            return false;
    1158        }
    1159        for (final CharSequence searchCharSequence : searchCharSequences) {
    1160            if (test.applyAsBoolean(cs, searchCharSequence)) {
    1161                return true;
    1162            }
    1163        }
    1164        return false;
    1165    }
    1166
    1167    /**
    1168     * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
    1169     *
    1170     * <p>
    1171     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
    1172     * return {@code false}.
    1173     * </p>
    1174     *
    1175     * <pre>
    1176     * StringUtils.containsAny(null, *)            = false
    1177     * StringUtils.containsAny("", *)              = false
    1178     * StringUtils.containsAny(*, null)            = false
    1179     * StringUtils.containsAny(*, [])              = false
    1180     * StringUtils.containsAny("abcd", "ab", null) = true
    1181     * StringUtils.containsAny("abcd", "ab", "cd") = true
    1182     * StringUtils.containsAny("abc", "d", "abc")  = true
    1183     * StringUtils.containsAny("abc", "D", "ABC")  = true
    1184     * StringUtils.containsAny("ABC", "d", "abc")  = true
    1185     * </pre>
    1186     *
    1187     * @param cs The CharSequence to check, may be null
    1188     * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
    1189     *        null as well.
    1190     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    1191     * @since 3.12.0
    1192     */
    1193    public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
    1194        return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
    1195    }
    1196
    1197    /**
    1198     * Checks if CharSequence contains a search CharSequence irrespective of case,
    1199     * handling {@code null}. Case-insensitivity is defined as by
    1200     * {@link String#equalsIgnoreCase(String)}.
    1201     *
    1202     * <p>A {@code null} CharSequence will return {@code false}.
    1203     *
    1204     * <pre>
    1205     * StringUtils.containsIgnoreCase(null, *)    = false
    1206     * StringUtils.containsIgnoreCase(*, null)    = false
    1207     * StringUtils.containsIgnoreCase("", "")     = true
    1208     * StringUtils.containsIgnoreCase("abc", "")  = true
    1209     * StringUtils.containsIgnoreCase("abc", "a") = true
    1210     * StringUtils.containsIgnoreCase("abc", "z") = false
    1211     * StringUtils.containsIgnoreCase("abc", "A") = true
    1212     * StringUtils.containsIgnoreCase("abc", "Z") = false
    1213     * </pre>
    1214     *
    1215     * @param str  the CharSequence to check, may be null
    1216     * @param searchStr  the CharSequence to find, may be null
    1217     * @return true if the CharSequence contains the search CharSequence irrespective of
    1218     * case or false if not or {@code null} string input
    1219     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
    1220     */
    1221    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1222        if (str == null || searchStr == null) {
    1223            return false;
    1224        }
    1225        final int len = searchStr.length();
    1226        final int max = str.length() - len;
    1227        for (int i = 0; i <= max; i++) {
    1228            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
    1229                return true;
    1230            }
    1231        }
    1232        return false;
    1233    }
    1234
    1235    /**
    1236     * Checks that the CharSequence does not contain certain characters.
    1237     *
    1238     * <p>A {@code null} CharSequence will return {@code true}.
    1239     * A {@code null} invalid character array will return {@code true}.
    1240     * An empty CharSequence (length()=0) always returns true.</p>
    1241     *
    1242     * <pre>
    1243     * StringUtils.containsNone(null, *)       = true
    1244     * StringUtils.containsNone(*, null)       = true
    1245     * StringUtils.containsNone("", *)         = true
    1246     * StringUtils.containsNone("ab", '')      = true
    1247     * StringUtils.containsNone("abab", 'xyz') = true
    1248     * StringUtils.containsNone("ab1", 'xyz')  = true
    1249     * StringUtils.containsNone("abz", 'xyz')  = false
    1250     * </pre>
    1251     *
    1252     * @param cs  the CharSequence to check, may be null
    1253     * @param searchChars  an array of invalid chars, may be null
    1254     * @return true if it contains none of the invalid chars, or is null
    1255     * @since 2.0
    1256     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
    1257     */
    1258    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    1259        if (cs == null || searchChars == null) {
    1260            return true;
    1261        }
    1262        final int csLen = cs.length();
    1263        final int csLast = csLen - 1;
    1264        final int searchLen = searchChars.length;
    1265        final int searchLast = searchLen - 1;
    1266        for (int i = 0; i < csLen; i++) {
    1267            final char ch = cs.charAt(i);
    1268            for (int j = 0; j < searchLen; j++) {
    1269                if (searchChars[j] == ch) {
    1270                    if (!Character.isHighSurrogate(ch)) {
    1271                        // ch is in the Basic Multilingual Plane
    1272                        return false;
    1273                    }
    1274                    if (j == searchLast) {
    1275                        // missing low surrogate, fine, like String.indexOf(String)
    1276                        return false;
    1277                    }
    1278                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1279                        return false;
    1280                    }
    1281                }
    1282            }
    1283        }
    1284        return true;
    1285    }
    1286
    1287    /**
    1288     * Checks that the CharSequence does not contain certain characters.
    1289     *
    1290     * <p>A {@code null} CharSequence will return {@code true}.
    1291     * A {@code null} invalid character array will return {@code true}.
    1292     * An empty String ("") always returns true.</p>
    1293     *
    1294     * <pre>
    1295     * StringUtils.containsNone(null, *)       = true
    1296     * StringUtils.containsNone(*, null)       = true
    1297     * StringUtils.containsNone("", *)         = true
    1298     * StringUtils.containsNone("ab", "")      = true
    1299     * StringUtils.containsNone("abab", "xyz") = true
    1300     * StringUtils.containsNone("ab1", "xyz")  = true
    1301     * StringUtils.containsNone("abz", "xyz")  = false
    1302     * </pre>
    1303     *
    1304     * @param cs  the CharSequence to check, may be null
    1305     * @param invalidChars  a String of invalid chars, may be null
    1306     * @return true if it contains none of the invalid chars, or is null
    1307     * @since 2.0
    1308     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    1309     */
    1310    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
    1311        if (invalidChars == null) {
    1312            return true;
    1313        }
    1314        return containsNone(cs, invalidChars.toCharArray());
    1315    }
    1316
    1317    /**
    1318     * Checks if the CharSequence contains only certain characters.
    1319     *
    1320     * <p>A {@code null} CharSequence will return {@code false}.
    1321     * A {@code null} valid character array will return {@code false}.
    1322     * An empty CharSequence (length()=0) always returns {@code true}.</p>
    1323     *
    1324     * <pre>
    1325     * StringUtils.containsOnly(null, *)       = false
    1326     * StringUtils.containsOnly(*, null)       = false
    1327     * StringUtils.containsOnly("", *)         = true
    1328     * StringUtils.containsOnly("ab", '')      = false
    1329     * StringUtils.containsOnly("abab", 'abc') = true
    1330     * StringUtils.containsOnly("ab1", 'abc')  = false
    1331     * StringUtils.containsOnly("abz", 'abc')  = false
    1332     * </pre>
    1333     *
    1334     * @param cs  the String to check, may be null
    1335     * @param valid  an array of valid chars, may be null
    1336     * @return true if it only contains valid chars and is non-null
    1337     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
    1338     */
    1339    public static boolean containsOnly(final CharSequence cs, final char... valid) {
    1340        // All these pre-checks are to maintain API with an older version
    1341        if (valid == null || cs == null) {
    1342            return false;
    1343        }
    1344        if (cs.length() == 0) {
    1345            return true;
    1346        }
    1347        if (valid.length == 0) {
    1348            return false;
    1349        }
    1350        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    1351    }
    1352
    1353    /**
    1354     * Checks if the CharSequence contains only certain characters.
    1355     *
    1356     * <p>A {@code null} CharSequence will return {@code false}.
    1357     * A {@code null} valid character String will return {@code false}.
    1358     * An empty String (length()=0) always returns {@code true}.</p>
    1359     *
    1360     * <pre>
    1361     * StringUtils.containsOnly(null, *)       = false
    1362     * StringUtils.containsOnly(*, null)       = false
    1363     * StringUtils.containsOnly("", *)         = true
    1364     * StringUtils.containsOnly("ab", "")      = false
    1365     * StringUtils.containsOnly("abab", "abc") = true
    1366     * StringUtils.containsOnly("ab1", "abc")  = false
    1367     * StringUtils.containsOnly("abz", "abc")  = false
    1368     * </pre>
    1369     *
    1370     * @param cs  the CharSequence to check, may be null
    1371     * @param validChars  a String of valid chars, may be null
    1372     * @return true if it only contains valid chars and is non-null
    1373     * @since 2.0
    1374     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    1375     */
    1376    public static boolean containsOnly(final CharSequence cs, final String validChars) {
    1377        if (cs == null || validChars == null) {
    1378            return false;
    1379        }
    1380        return containsOnly(cs, validChars.toCharArray());
    1381    }
    1382
    1383    /**
    1384     * Check whether the given CharSequence contains any whitespace characters.
    1385     *
    1386     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1387     *
    1388     * @param seq the CharSequence to check (may be {@code null})
    1389     * @return {@code true} if the CharSequence is not empty and
    1390     * contains at least 1 (breaking) whitespace character
    1391     * @since 3.0
    1392     */
    1393    // From org.springframework.util.StringUtils, under Apache License 2.0
    1394    public static boolean containsWhitespace(final CharSequence seq) {
    1395        if (isEmpty(seq)) {
    1396            return false;
    1397        }
    1398        final int strLen = seq.length();
    1399        for (int i = 0; i < strLen; i++) {
    1400            if (Character.isWhitespace(seq.charAt(i))) {
    1401                return true;
    1402            }
    1403        }
    1404        return false;
    1405    }
    1406
    1407    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
    1408        for (int i = 0; i < decomposed.length(); i++) {
    1409            final char charAt = decomposed.charAt(i);
    1410            switch (charAt) {
    1411            case '\u0141':
    1412                decomposed.setCharAt(i, 'L');
    1413                break;
    1414            case '\u0142':
    1415                decomposed.setCharAt(i, 'l');
    1416                break;
    1417            // D with stroke
    1418            case '\u0110':
    1419                // LATIN CAPITAL LETTER D WITH STROKE
    1420                decomposed.setCharAt(i, 'D');
    1421                break;
    1422            case '\u0111':
    1423                // LATIN SMALL LETTER D WITH STROKE
    1424                decomposed.setCharAt(i, 'd');
    1425                break;
    1426            // I with bar
    1427            case '\u0197':
    1428                decomposed.setCharAt(i, 'I');
    1429                break;
    1430            case '\u0268':
    1431                decomposed.setCharAt(i, 'i');
    1432                break;
    1433            case '\u1D7B':
    1434                decomposed.setCharAt(i, 'I');
    1435                break;
    1436            case '\u1DA4':
    1437                decomposed.setCharAt(i, 'i');
    1438                break;
    1439            case '\u1DA7':
    1440                decomposed.setCharAt(i, 'I');
    1441                break;
    1442            // U with bar
    1443            case '\u0244':
    1444                // LATIN CAPITAL LETTER U BAR
    1445                decomposed.setCharAt(i, 'U');
    1446                break;
    1447            case '\u0289':
    1448                // LATIN SMALL LETTER U BAR
    1449                decomposed.setCharAt(i, 'u');
    1450                break;
    1451            case '\u1D7E':
    1452                // LATIN SMALL CAPITAL LETTER U WITH STROKE
    1453                decomposed.setCharAt(i, 'U');
    1454                break;
    1455            case '\u1DB6':
    1456                // MODIFIER LETTER SMALL U BAR
    1457                decomposed.setCharAt(i, 'u');
    1458                break;
    1459            // T with stroke
    1460            case '\u0166':
    1461                // LATIN CAPITAL LETTER T WITH STROKE
    1462                decomposed.setCharAt(i, 'T');
    1463                break;
    1464            case '\u0167':
    1465                // LATIN SMALL LETTER T WITH STROKE
    1466                decomposed.setCharAt(i, 't');
    1467                break;
    1468            default:
    1469                break;
    1470            }
    1471        }
    1472    }
    1473
    1474    /**
    1475     * Counts how many times the char appears in the given string.
    1476     *
    1477     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1478     *
    1479     * <pre>
    1480     * StringUtils.countMatches(null, *)     = 0
    1481     * StringUtils.countMatches("", *)       = 0
    1482     * StringUtils.countMatches("abba", 0)   = 0
    1483     * StringUtils.countMatches("abba", 'a') = 2
    1484     * StringUtils.countMatches("abba", 'b') = 2
    1485     * StringUtils.countMatches("abba", 'x') = 0
    1486     * </pre>
    1487     *
    1488     * @param str  the CharSequence to check, may be null
    1489     * @param ch  the char to count
    1490     * @return the number of occurrences, 0 if the CharSequence is {@code null}
    1491     * @since 3.4
    1492     */
    1493    public static int countMatches(final CharSequence str, final char ch) {
    1494        if (isEmpty(str)) {
    1495            return 0;
    1496        }
    1497        int count = 0;
    1498        // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
    1499        for (int i = 0; i < str.length(); i++) {
    1500            if (ch == str.charAt(i)) {
    1501                count++;
    1502            }
    1503        }
    1504        return count;
    1505    }
    1506
    1507    /**
    1508     * Counts how many times the substring appears in the larger string.
    1509     * Note that the code only counts non-overlapping matches.
    1510     *
    1511     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    1512     *
    1513     * <pre>
    1514     * StringUtils.countMatches(null, *)        = 0
    1515     * StringUtils.countMatches("", *)          = 0
    1516     * StringUtils.countMatches("abba", null)   = 0
    1517     * StringUtils.countMatches("abba", "")     = 0
    1518     * StringUtils.countMatches("abba", "a")    = 2
    1519     * StringUtils.countMatches("abba", "ab")   = 1
    1520     * StringUtils.countMatches("abba", "xxx")  = 0
    1521     * StringUtils.countMatches("ababa", "aba") = 1
    1522     * </pre>
    1523     *
    1524     * @param str  the CharSequence to check, may be null
    1525     * @param sub  the substring to count, may be null
    1526     * @return the number of occurrences, 0 if either CharSequence is {@code null}
    1527     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
    1528     */
    1529    public static int countMatches(final CharSequence str, final CharSequence sub) {
    1530        if (isEmpty(str) || isEmpty(sub)) {
    1531            return 0;
    1532        }
    1533        int count = 0;
    1534        int idx = 0;
    1535        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
    1536            count++;
    1537            idx += sub.length();
    1538        }
    1539        return count;
    1540    }
    1541
    1542    /**
    1543     * Returns either the passed in CharSequence, or if the CharSequence is
    1544     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.
    1545     *
    1546     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1547     *
    1548     * <pre>
    1549     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
    1550     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
    1551     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
    1552     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
    1553     * StringUtils.defaultIfBlank("", null)      = null
    1554     * </pre>
    1555     * @param <T> the specific kind of CharSequence
    1556     * @param str the CharSequence to check, may be null
    1557     * @param defaultStr  the default CharSequence to return
    1558     *  if the input is whitespace, empty ("") or {@code null}, may be null
    1559     * @return the passed in CharSequence, or the default
    1560     * @see StringUtils#defaultString(String, String)
    1561     */
    1562    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
    1563        return isBlank(str) ? defaultStr : str;
    1564    }
    1565
    1566    /**
    1567     * Returns either the passed in CharSequence, or if the CharSequence is
    1568     * empty or {@code null}, the value of {@code defaultStr}.
    1569     *
    1570     * <pre>
    1571     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    1572     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    1573     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
    1574     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    1575     * StringUtils.defaultIfEmpty("", null)      = null
    1576     * </pre>
    1577     * @param <T> the specific kind of CharSequence
    1578     * @param str  the CharSequence to check, may be null
    1579     * @param defaultStr  the default CharSequence to return
    1580     *  if the input is empty ("") or {@code null}, may be null
    1581     * @return the passed in CharSequence, or the default
    1582     * @see StringUtils#defaultString(String, String)
    1583     */
    1584    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
    1585        return isEmpty(str) ? defaultStr : str;
    1586    }
    1587
    1588    /**
    1589     * Returns either the passed in String,
    1590     * or if the String is {@code null}, an empty String ("").
    1591     *
    1592     * <pre>
    1593     * StringUtils.defaultString(null)  = ""
    1594     * StringUtils.defaultString("")    = ""
    1595     * StringUtils.defaultString("bat") = "bat"
    1596     * </pre>
    1597     *
    1598     * @see Objects#toString(Object, String)
    1599     * @see String#valueOf(Object)
    1600     * @param str  the String to check, may be null
    1601     * @return the passed in String, or the empty String if it
    1602     *  was {@code null}
    1603     */
    1604    public static String defaultString(final String str) {
    1605        return Objects.toString(str, EMPTY);
    1606    }
    1607
    1608    /**
    1609     * Returns either the given String, or if the String is
    1610     * {@code null}, {@code nullDefault}.
    1611     *
    1612     * <pre>
    1613     * StringUtils.defaultString(null, "NULL")  = "NULL"
    1614     * StringUtils.defaultString("", "NULL")    = ""
    1615     * StringUtils.defaultString("bat", "NULL") = "bat"
    1616     * </pre>
    1617     * <p>
    1618     * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
    1619     * </p>
    1620     * <pre>
    1621     * Objects.toString(null, "NULL")  = "NULL"
    1622     * Objects.toString("", "NULL")    = ""
    1623     * Objects.toString("bat", "NULL") = "bat"
    1624     * </pre>
    1625     *
    1626     * @see Objects#toString(Object, String)
    1627     * @see String#valueOf(Object)
    1628     * @param str  the String to check, may be null
    1629     * @param nullDefault  the default String to return
    1630     *  if the input is {@code null}, may be null
    1631     * @return the passed in String, or the default if it was {@code null}
    1632     * @deprecated Use {@link Objects#toString(Object, String)}
    1633     */
    1634    @Deprecated
    1635    public static String defaultString(final String str, final String nullDefault) {
    1636        return Objects.toString(str, nullDefault);
    1637    }
    1638
    1639    /**
    1640     * Deletes all whitespaces from a String as defined by
    1641     * {@link Character#isWhitespace(char)}.
    1642     *
    1643     * <pre>
    1644     * StringUtils.deleteWhitespace(null)         = null
    1645     * StringUtils.deleteWhitespace("")           = ""
    1646     * StringUtils.deleteWhitespace("abc")        = "abc"
    1647     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    1648     * </pre>
    1649     *
    1650     * @param str  the String to delete whitespace from, may be null
    1651     * @return the String without whitespaces, {@code null} if null String input
    1652     */
    1653    public static String deleteWhitespace(final String str) {
    1654        if (isEmpty(str)) {
    1655            return str;
    1656        }
    1657        final int sz = str.length();
    1658        final char[] chs = new char[sz];
    1659        int count = 0;
    1660        for (int i = 0; i < sz; i++) {
    1661            if (!Character.isWhitespace(str.charAt(i))) {
    1662                chs[count++] = str.charAt(i);
    1663            }
    1664        }
    1665        if (count == sz) {
    1666            return str;
    1667        }
    1668        if (count == 0) {
    1669            return EMPTY;
    1670        }
    1671        return new String(chs, 0, count);
    1672    }
    1673
    1674    /**
    1675     * Compares two Strings, and returns the portion where they differ.
    1676     * More precisely, return the remainder of the second String,
    1677     * starting from where it's different from the first. This means that
    1678     * the difference between "abc" and "ab" is the empty String and not "c".
    1679     *
    1680     * <p>For example,
    1681     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
    1682     *
    1683     * <pre>
    1684     * StringUtils.difference(null, null)       = null
    1685     * StringUtils.difference("", "")           = ""
    1686     * StringUtils.difference("", "abc")        = "abc"
    1687     * StringUtils.difference("abc", "")        = ""
    1688     * StringUtils.difference("abc", "abc")     = ""
    1689     * StringUtils.difference("abc", "ab")      = ""
    1690     * StringUtils.difference("ab", "abxyz")    = "xyz"
    1691     * StringUtils.difference("abcde", "abxyz") = "xyz"
    1692     * StringUtils.difference("abcde", "xyz")   = "xyz"
    1693     * </pre>
    1694     *
    1695     * @param str1  the first String, may be null
    1696     * @param str2  the second String, may be null
    1697     * @return the portion of str2 where it differs from str1; returns the
    1698     * empty String if they are equal
    1699     * @see #indexOfDifference(CharSequence,CharSequence)
    1700     * @since 2.0
    1701     */
    1702    public static String difference(final String str1, final String str2) {
    1703        if (str1 == null) {
    1704            return str2;
    1705        }
    1706        if (str2 == null) {
    1707            return str1;
    1708        }
    1709        final int at = indexOfDifference(str1, str2);
    1710        if (at == INDEX_NOT_FOUND) {
    1711            return EMPTY;
    1712        }
    1713        return str2.substring(at);
    1714    }
    1715
    1716    /**
    1717     * Check if a CharSequence ends with a specified suffix.
    1718     *
    1719     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1720     * references are considered to be equal. The comparison is case-sensitive.</p>
    1721     *
    1722     * <pre>
    1723     * StringUtils.endsWith(null, null)      = true
    1724     * StringUtils.endsWith(null, "def")     = false
    1725     * StringUtils.endsWith("abcdef", null)  = false
    1726     * StringUtils.endsWith("abcdef", "def") = true
    1727     * StringUtils.endsWith("ABCDEF", "def") = false
    1728     * StringUtils.endsWith("ABCDEF", "cde") = false
    1729     * StringUtils.endsWith("ABCDEF", "")    = true
    1730     * </pre>
    1731     *
    1732     * @see String#endsWith(String)
    1733     * @param str  the CharSequence to check, may be null
    1734     * @param suffix the suffix to find, may be null
    1735     * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
    1736     *  both {@code null}
    1737     * @since 2.4
    1738     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
    1739     */
    1740    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
    1741        return endsWith(str, suffix, false);
    1742    }
    1743
    1744    /**
    1745     * Check if a CharSequence ends with a specified suffix (optionally case insensitive).
    1746     *
    1747     * @see String#endsWith(String)
    1748     * @param str  the CharSequence to check, may be null
    1749     * @param suffix the suffix to find, may be null
    1750     * @param ignoreCase indicates whether the compare should ignore case
    1751     *  (case-insensitive) or not.
    1752     * @return {@code true} if the CharSequence starts with the prefix or
    1753     *  both {@code null}
    1754     */
    1755    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
    1756        if (str == null || suffix == null) {
    1757            return str == suffix;
    1758        }
    1759        if (suffix.length() > str.length()) {
    1760            return false;
    1761        }
    1762        final int strOffset = str.length() - suffix.length();
    1763        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
    1764    }
    1765
    1766    /**
    1767     * Check if a CharSequence ends with any of the provided case-sensitive suffixes.
    1768     *
    1769     * <pre>
    1770     * StringUtils.endsWithAny(null, null)                  = false
    1771     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
    1772     * StringUtils.endsWithAny("abcxyz", null)              = false
    1773     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
    1774     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
    1775     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    1776     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
    1777     * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
    1778     * </pre>
    1779     *
    1780     * @param sequence  the CharSequence to check, may be null
    1781     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
    1782     * @see StringUtils#endsWith(CharSequence, CharSequence)
    1783     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    1784     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
    1785     * @since 3.0
    1786     */
    1787    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    1788        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    1789            return false;
    1790        }
    1791        for (final CharSequence searchString : searchStrings) {
    1792            if (endsWith(sequence, searchString)) {
    1793                return true;
    1794            }
    1795        }
    1796        return false;
    1797    }
    1798
    1799    /**
    1800     * Case insensitive check if a CharSequence ends with a specified suffix.
    1801     *
    1802     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1803     * references are considered to be equal. The comparison is case insensitive.</p>
    1804     *
    1805     * <pre>
    1806     * StringUtils.endsWithIgnoreCase(null, null)      = true
    1807     * StringUtils.endsWithIgnoreCase(null, "def")     = false
    1808     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    1809     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    1810     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    1811     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    1812     * </pre>
    1813     *
    1814     * @see String#endsWith(String)
    1815     * @param str  the CharSequence to check, may be null
    1816     * @param suffix the suffix to find, may be null
    1817     * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
    1818     *  both {@code null}
    1819     * @since 2.4
    1820     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
    1821     */
    1822    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
    1823        return endsWith(str, suffix, true);
    1824    }
    1825
    1826    /**
    1827     * Compares two CharSequences, returning {@code true} if they represent
    1828     * equal sequences of characters.
    1829     *
    1830     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1831     * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
    1832     *
    1833     * <pre>
    1834     * StringUtils.equals(null, null)   = true
    1835     * StringUtils.equals(null, "abc")  = false
    1836     * StringUtils.equals("abc", null)  = false
    1837     * StringUtils.equals("abc", "abc") = true
    1838     * StringUtils.equals("abc", "ABC") = false
    1839     * </pre>
    1840     *
    1841     * @param cs1  the first CharSequence, may be {@code null}
    1842     * @param cs2  the second CharSequence, may be {@code null}
    1843     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
    1844     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    1845     * @see Object#equals(Object)
    1846     * @see #equalsIgnoreCase(CharSequence, CharSequence)
    1847     */
    1848    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
    1849        if (cs1 == cs2) {
    1850            return true;
    1851        }
    1852        if (cs1 == null || cs2 == null) {
    1853            return false;
    1854        }
    1855        if (cs1.length() != cs2.length()) {
    1856            return false;
    1857        }
    1858        if (cs1 instanceof String && cs2 instanceof String) {
    1859            return cs1.equals(cs2);
    1860        }
    1861        // Step-wise comparison
    1862        final int length = cs1.length();
    1863        for (int i = 0; i < length; i++) {
    1864            if (cs1.charAt(i) != cs2.charAt(i)) {
    1865                return false;
    1866            }
    1867        }
    1868        return true;
    1869    }
    1870
    1871    /**
    1872     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1873     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
    1874     *
    1875     * <pre>
    1876     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
    1877     * StringUtils.equalsAny(null, null, null)    = true
    1878     * StringUtils.equalsAny(null, "abc", "def")  = false
    1879     * StringUtils.equalsAny("abc", null, "def")  = false
    1880     * StringUtils.equalsAny("abc", "abc", "def") = true
    1881     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
    1882     * </pre>
    1883     *
    1884     * @param string to compare, may be {@code null}.
    1885     * @param searchStrings a vararg of strings, may be {@code null}.
    1886     * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
    1887     * {@code false} if {@code searchStrings} is null or contains no matches.
    1888     * @since 3.5
    1889     */
    1890    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
    1891        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1892            for (final CharSequence next : searchStrings) {
    1893                if (equals(string, next)) {
    1894                    return true;
    1895                }
    1896            }
    1897        }
    1898        return false;
    1899    }
    1900
    1901    /**
    1902     * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
    1903     * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
    1904     *
    1905     * <pre>
    1906     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
    1907     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
    1908     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
    1909     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
    1910     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
    1911     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
    1912     * </pre>
    1913     *
    1914     * @param string to compare, may be {@code null}.
    1915     * @param searchStrings a vararg of strings, may be {@code null}.
    1916     * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
    1917     * {@code false} if {@code searchStrings} is null or contains no matches.
    1918     * @since 3.5
    1919     */
    1920    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
    1921        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1922            for (final CharSequence next : searchStrings) {
    1923                if (equalsIgnoreCase(string, next)) {
    1924                    return true;
    1925                }
    1926            }
    1927        }
    1928        return false;
    1929    }
    1930
    1931    /**
    1932     * Compares two CharSequences, returning {@code true} if they represent
    1933     * equal sequences of characters, ignoring case.
    1934     *
    1935     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1936     * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
    1937     *
    1938     * <pre>
    1939     * StringUtils.equalsIgnoreCase(null, null)   = true
    1940     * StringUtils.equalsIgnoreCase(null, "abc")  = false
    1941     * StringUtils.equalsIgnoreCase("abc", null)  = false
    1942     * StringUtils.equalsIgnoreCase("abc", "abc") = true
    1943     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    1944     * </pre>
    1945     *
    1946     * @param cs1  the first CharSequence, may be {@code null}
    1947     * @param cs2  the second CharSequence, may be {@code null}
    1948     * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
    1949     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
    1950     * @see #equals(CharSequence, CharSequence)
    1951     */
    1952    public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
    1953        if (cs1 == cs2) {
    1954            return true;
    1955        }
    1956        if (cs1 == null || cs2 == null) {
    1957            return false;
    1958        }
    1959        if (cs1.length() != cs2.length()) {
    1960            return false;
    1961        }
    1962        return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
    1963    }
    1964
    1965    /**
    1966     * Returns the first value in the array which is not empty (""),
    1967     * {@code null} or whitespace only.
    1968     *
    1969     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    1970     *
    1971     * <p>If all values are blank or the array is {@code null}
    1972     * or empty then {@code null} is returned.</p>
    1973     *
    1974     * <pre>
    1975     * StringUtils.firstNonBlank(null, null, null)     = null
    1976     * StringUtils.firstNonBlank(null, "", " ")        = null
    1977     * StringUtils.firstNonBlank("abc")                = "abc"
    1978     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
    1979     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
    1980     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
    1981     * StringUtils.firstNonBlank()                     = null
    1982     * </pre>
    1983     *
    1984     * @param <T> the specific kind of CharSequence
    1985     * @param values  the values to test, may be {@code null} or empty
    1986     * @return the first value from {@code values} which is not blank,
    1987     *  or {@code null} if there are no non-blank values
    1988     * @since 3.8
    1989     */
    1990    @SafeVarargs
    1991    public static <T extends CharSequence> T firstNonBlank(final T... values) {
    1992        if (values != null) {
    1993            for (final T val : values) {
    1994                if (isNotBlank(val)) {
    1995                    return val;
    1996                }
    1997            }
    1998        }
    1999        return null;
    2000    }
    2001
    2002    /**
    2003     * Returns the first value in the array which is not empty.
    2004     *
    2005     * <p>If all values are empty or the array is {@code null}
    2006     * or empty then {@code null} is returned.</p>
    2007     *
    2008     * <pre>
    2009     * StringUtils.firstNonEmpty(null, null, null)   = null
    2010     * StringUtils.firstNonEmpty(null, null, "")     = null
    2011     * StringUtils.firstNonEmpty(null, "", " ")      = " "
    2012     * StringUtils.firstNonEmpty("abc")              = "abc"
    2013     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
    2014     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
    2015     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
    2016     * StringUtils.firstNonEmpty()                   = null
    2017     * </pre>
    2018     *
    2019     * @param <T> the specific kind of CharSequence
    2020     * @param values  the values to test, may be {@code null} or empty
    2021     * @return the first value from {@code values} which is not empty,
    2022     *  or {@code null} if there are no non-empty values
    2023     * @since 3.8
    2024     */
    2025    @SafeVarargs
    2026    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
    2027        if (values != null) {
    2028            for (final T val : values) {
    2029                if (isNotEmpty(val)) {
    2030                    return val;
    2031                }
    2032            }
    2033        }
    2034        return null;
    2035    }
    2036
    2037    /**
    2038     * Calls {@link String#getBytes(Charset)} in a null-safe manner.
    2039     *
    2040     * @param string input string
    2041     * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
    2042     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
    2043     * @see String#getBytes(Charset)
    2044     * @since 3.10
    2045     */
    2046    public static byte[] getBytes(final String string, final Charset charset) {
    2047        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
    2048    }
    2049
    2050    /**
    2051     * Calls {@link String#getBytes(String)} in a null-safe manner.
    2052     *
    2053     * @param string input string
    2054     * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
    2055     * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
    2056     * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
    2057     * @see String#getBytes(String)
    2058     * @since 3.10
    2059     */
    2060    public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
    2061        return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
    2062    }
    2063
    2064    /**
    2065     * Compares all Strings in an array and returns the initial sequence of
    2066     * characters that is common to all of them.
    2067     *
    2068     * <p>For example,
    2069     * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
    2070     *
    2071     * <pre>
    2072     * StringUtils.getCommonPrefix(null)                             = ""
    2073     * StringUtils.getCommonPrefix(new String[] {})                  = ""
    2074     * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
    2075     * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
    2076     * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
    2077     * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
    2078     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    2079     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    2080     * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
    2081     * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
    2082     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
    2083     * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
    2084     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
    2085     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
    2086     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
    2087     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
    2088     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    2089     * </pre>
    2090     *
    2091     * @param strs  array of String objects, entries may be null
    2092     * @return the initial sequence of characters that are common to all Strings
    2093     * in the array; empty String if the array is null, the elements are all null
    2094     * or if there is no common prefix.
    2095     * @since 2.4
    2096     */
    2097    public static String getCommonPrefix(final String... strs) {
    2098        if (ArrayUtils.isEmpty(strs)) {
    2099            return EMPTY;
    2100        }
    2101        final int smallestIndexOfDiff = indexOfDifference(strs);
    2102        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    2103            // all strings were identical
    2104            if (strs[0] == null) {
    2105                return EMPTY;
    2106            }
    2107            return strs[0];
    2108        }
    2109        if (smallestIndexOfDiff == 0) {
    2110            // there were no common initial characters
    2111            return EMPTY;
    2112        }
    2113        // we found a common initial character sequence
    2114        return strs[0].substring(0, smallestIndexOfDiff);
    2115    }
    2116
    2117    /**
    2118     * Checks if a String {@code str} contains Unicode digits,
    2119     * if yes then concatenate all the digits in {@code str} and return it as a String.
    2120     *
    2121     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
    2122     *
    2123     * <pre>
    2124     * StringUtils.getDigits(null)                 = null
    2125     * StringUtils.getDigits("")                   = ""
    2126     * StringUtils.getDigits("abc")                = ""
    2127     * StringUtils.getDigits("1000$")              = "1000"
    2128     * StringUtils.getDigits("1123~45")            = "112345"
    2129     * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
    2130     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
    2131     * </pre>
    2132     *
    2133     * @param str the String to extract digits from, may be null
    2134     * @return String with only digits,
    2135     *           or an empty ("") String if no digits found,
    2136     *           or {@code null} String if {@code str} is null
    2137     * @since 3.6
    2138     */
    2139    public static String getDigits(final String str) {
    2140        if (isEmpty(str)) {
    2141            return str;
    2142        }
    2143        final int sz = str.length();
    2144        final StringBuilder strDigits = new StringBuilder(sz);
    2145        for (int i = 0; i < sz; i++) {
    2146            final char tempChar = str.charAt(i);
    2147            if (Character.isDigit(tempChar)) {
    2148                strDigits.append(tempChar);
    2149            }
    2150        }
    2151        return strDigits.toString();
    2152    }
    2153
    2154    /**
    2155     * Find the Fuzzy Distance which indicates the similarity score between two Strings.
    2156     *
    2157     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
    2158     * TextMate, Atom and others. One point is given for every matched character. Subsequent
    2159     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
    2160     *
    2161     * <pre>
    2162     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
    2163     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
    2164     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
    2165     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
    2166     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
    2167     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
    2168     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
    2169     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
    2170     * </pre>
    2171     *
    2172     * @param term a full term that should be matched against, must not be null
    2173     * @param query the query that will be matched against a term, must not be null
    2174     * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
    2175     *  both Strings to lower case.
    2176     * @return result score
    2177     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
    2178     * @since 3.4
    2179     * @deprecated As of 3.6, use Apache Commons Text
    2180     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
    2181     * FuzzyScore</a> instead
    2182     */
    2183    @Deprecated
    2184    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
    2185        if (term == null || query == null) {
    2186            throw new IllegalArgumentException("Strings must not be null");
    2187        }
    2188        if (locale == null) {
    2189            throw new IllegalArgumentException("Locale must not be null");
    2190        }
    2191
    2192        // fuzzy logic is case-insensitive. We normalize the Strings to lower
    2193        // case right from the start. Turning characters to lower case
    2194        // via Character.toLowerCase(char) is unfortunately insufficient
    2195        // as it does not accept a locale.
    2196        final String termLowerCase = term.toString().toLowerCase(locale);
    2197        final String queryLowerCase = query.toString().toLowerCase(locale);
    2198
    2199        // the resulting score
    2200        int score = 0;
    2201
    2202        // the position in the term which will be scanned next for potential
    2203        // query character matches
    2204        int termIndex = 0;
    2205
    2206        // index of the previously matched character in the term
    2207        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
    2208
    2209        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
    2210            final char queryChar = queryLowerCase.charAt(queryIndex);
    2211
    2212            boolean termCharacterMatchFound = false;
    2213            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
    2214                final char termChar = termLowerCase.charAt(termIndex);
    2215
    2216                if (queryChar == termChar) {
    2217                    // simple character matches result in one point
    2218                    score++;
    2219
    2220                    // subsequent character matches further improve
    2221                    // the score.
    2222                    if (previousMatchingCharacterIndex + 1 == termIndex) {
    2223                        score += 2;
    2224                    }
    2225
    2226                    previousMatchingCharacterIndex = termIndex;
    2227
    2228                    // we can leave the nested loop. Every character in the
    2229                    // query can match at most one character in the term.
    2230                    termCharacterMatchFound = true;
    2231                }
    2232            }
    2233        }
    2234
    2235        return score;
    2236    }
    2237
    2238    /**
    2239     * Returns either the passed in CharSequence, or if the CharSequence is
    2240     * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.
    2241     *
    2242     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    2243     *
    2244     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2245     *
    2246     * <pre>
    2247     * {@code
    2248     * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
    2249     * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
    2250     * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
    2251     * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
    2252     * StringUtils.getIfBlank("", () -> null)       = null
    2253     * StringUtils.getIfBlank("", null)             = null
    2254     * }</pre>
    2255     * @param <T> the specific kind of CharSequence
    2256     * @param str the CharSequence to check, may be null
    2257     * @param defaultSupplier the supplier of default CharSequence to return
    2258     *  if the input is whitespace, empty ("") or {@code null}, may be null
    2259     * @return the passed in CharSequence, or the default
    2260     * @see StringUtils#defaultString(String, String)
    2261     * @since 3.10
    2262     */
    2263    public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
    2264        return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
    2265    }
    2266
    2267    /**
    2268     * Returns either the passed in CharSequence, or if the CharSequence is
    2269     * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
    2270     *
    2271     * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
    2272     *
    2273     * <pre>
    2274     * {@code
    2275     * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
    2276     * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
    2277     * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
    2278     * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
    2279     * StringUtils.getIfEmpty("", () -> null)        = null
    2280     * StringUtils.getIfEmpty("", null)              = null
    2281     * }
    2282     * </pre>
    2283     * @param <T> the specific kind of CharSequence
    2284     * @param str  the CharSequence to check, may be null
    2285     * @param defaultSupplier  the supplier of default CharSequence to return
    2286     *  if the input is empty ("") or {@code null}, may be null
    2287     * @return the passed in CharSequence, or the default
    2288     * @see StringUtils#defaultString(String, String)
    2289     * @since 3.10
    2290     */
    2291    public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
    2292        return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
    2293    }
    2294
    2295    /**
    2296     * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
    2297     *
    2298     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
    2299     * Winkler increased this measure for matching initial characters.</p>
    2300     *
    2301     * <p>This implementation is based on the Jaro Winkler similarity algorithm
    2302     * from <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
    2303     *
    2304     * <pre>
    2305     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
    2306     * StringUtils.getJaroWinklerDistance("", "")              = 0.0
    2307     * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
    2308     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
    2309     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
    2310     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
    2311     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
    2312     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
    2313     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
    2314     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
    2315     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
    2316     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
    2317     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
    2318     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
    2319     * </pre>
    2320     *
    2321     * @param first the first String, must not be null
    2322     * @param second the second String, must not be null
    2323     * @return result distance
    2324     * @throws IllegalArgumentException if either String input {@code null}
    2325     * @since 3.3
    2326     * @deprecated As of 3.6, use Apache Commons Text
    2327     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
    2328     * JaroWinklerDistance</a> instead
    2329     */
    2330    @Deprecated
    2331    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
    2332        final double DEFAULT_SCALING_FACTOR = 0.1;
    2333
    2334        if (first == null || second == null) {
    2335            throw new IllegalArgumentException("Strings must not be null");
    2336        }
    2337
    2338        final int[] mtp = matches(first, second);
    2339        final double m = mtp[0];
    2340        if (m == 0) {
    2341            return 0D;
    2342        }
    2343        final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
    2344        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
    2345        return Math.round(jw * 100.0D) / 100.0D;
    2346    }
    2347
    2348    /**
    2349     * Find the Levenshtein distance between two Strings.
    2350     *
    2351     * <p>This is the number of changes needed to change one String into
    2352     * another, where each change is a single character modification (deletion,
    2353     * insertion or substitution).</p>
    2354     *
    2355     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
    2356     * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
    2357     * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
    2358     *
    2359     * <pre>
    2360     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    2361     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    2362     * StringUtils.getLevenshteinDistance("", "")              = 0
    2363     * StringUtils.getLevenshteinDistance("", "a")             = 1
    2364     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    2365     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    2366     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    2367     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    2368     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    2369     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    2370     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    2371     * </pre>
    2372     *
    2373     * @param s  the first String, must not be null
    2374     * @param t  the second String, must not be null
    2375     * @return result distance
    2376     * @throws IllegalArgumentException if either String input {@code null}
    2377     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
    2378     * getLevenshteinDistance(CharSequence, CharSequence)
    2379     * @deprecated As of 3.6, use Apache Commons Text
    2380     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2381     * LevenshteinDistance</a> instead
    2382     */
    2383    @Deprecated
    2384    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    2385        if (s == null || t == null) {
    2386            throw new IllegalArgumentException("Strings must not be null");
    2387        }
    2388
    2389        int n = s.length();
    2390        int m = t.length();
    2391
    2392        if (n == 0) {
    2393            return m;
    2394        }
    2395        if (m == 0) {
    2396            return n;
    2397        }
    2398
    2399        if (n > m) {
    2400            // swap the input strings to consume less memory
    2401            final CharSequence tmp = s;
    2402            s = t;
    2403            t = tmp;
    2404            n = m;
    2405            m = t.length();
    2406        }
    2407
    2408        final int[] p = new int[n + 1];
    2409        // indexes into strings s and t
    2410        int i; // iterates through s
    2411        int j; // iterates through t
    2412        int upperleft;
    2413        int upper;
    2414
    2415        char jOfT; // jth character of t
    2416        int cost;
    2417
    2418        for (i = 0; i <= n; i++) {
    2419            p[i] = i;
    2420        }
    2421
    2422        for (j = 1; j <= m; j++) {
    2423            upperleft = p[0];
    2424            jOfT = t.charAt(j - 1);
    2425            p[0] = j;
    2426
    2427            for (i = 1; i <= n; i++) {
    2428                upper = p[i];
    2429                cost = s.charAt(i - 1) == jOfT ? 0 : 1;
    2430                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    2431                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
    2432                upperleft = upper;
    2433            }
    2434        }
    2435
    2436        return p[n];
    2437    }
    2438
    2439    /**
    2440     * Find the Levenshtein distance between two Strings if it's less than or equal to a given
    2441     * threshold.
    2442     *
    2443     * <p>This is the number of changes needed to change one String into
    2444     * another, where each change is a single character modification (deletion,
    2445     * insertion or substitution).</p>
    2446     *
    2447     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
    2448     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
    2449     * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
    2450     *
    2451     * <pre>
    2452     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
    2453     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
    2454     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
    2455     * StringUtils.getLevenshteinDistance("", "", 0)              = 0
    2456     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
    2457     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
    2458     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
    2459     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
    2460     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
    2461     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
    2462     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
    2463     * </pre>
    2464     *
    2465     * @param s  the first String, must not be null
    2466     * @param t  the second String, must not be null
    2467     * @param threshold the target threshold, must not be negative
    2468     * @return result distance, or {@code -1} if the distance would be greater than the threshold
    2469     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
    2470     * @deprecated As of 3.6, use Apache Commons Text
    2471     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    2472     * LevenshteinDistance</a> instead
    2473     */
    2474    @Deprecated
    2475    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
    2476        if (s == null || t == null) {
    2477            throw new IllegalArgumentException("Strings must not be null");
    2478        }
    2479        if (threshold < 0) {
    2480            throw new IllegalArgumentException("Threshold must not be negative");
    2481        }
    2482
    2483        /*
    2484        This implementation only computes the distance if it's less than or equal to the
    2485        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    2486        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    2487        computing a diagonal stripe of width 2k + 1 of the cost table.
    2488        It is also possible to use this to compute the unbounded Levenshtein distance by starting
    2489        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    2490        d is the distance.
    2491
    2492        One subtlety comes from needing to ignore entries on the border of our stripe
    2493        eg.
    2494        p[] = |#|#|#|*
    2495        d[] =  *|#|#|#|
    2496        We must ignore the entry to the left of the leftmost member
    2497        We must ignore the entry above the rightmost member
    2498
    2499        Another subtlety comes from our stripe running off the matrix if the strings aren't
    2500        of the same size.  Since string s is always swapped to be the shorter of the two,
    2501        the stripe will always run off to the upper right instead of the lower left of the matrix.
    2502
    2503        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    2504        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
    2505
    2506           1 2 3 4 5
    2507        1 |#|#| | | |
    2508        2 |#|#|#| | |
    2509        3 | |#|#|#| |
    2510        4 | | |#|#|#|
    2511        5 | | | |#|#|
    2512        6 | | | | |#|
    2513        7 | | | | | |
    2514
    2515        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    2516        into one of length 7 in edit distance of 1.
    2517
    2518        Additionally, this implementation decreases memory usage by using two
    2519        single-dimensional arrays and swapping them back and forth instead of allocating
    2520        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    2521        when it's detected that the stripe has run off the matrix and initially filling the arrays with
    2522        large values so that entries we don't compute are ignored.
    2523
    2524        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
    2525         */
    2526
    2527        int n = s.length(); // length of s
    2528        int m = t.length(); // length of t
    2529
    2530        // if one string is empty, the edit distance is necessarily the length of the other
    2531        if (n == 0) {
    2532            return m <= threshold ? m : -1;
    2533        }
    2534        if (m == 0) {
    2535            return n <= threshold ? n : -1;
    2536        }
    2537        if (Math.abs(n - m) > threshold) {
    2538            // no need to calculate the distance if the length difference is greater than the threshold
    2539            return -1;
    2540        }
    2541
    2542        if (n > m) {
    2543            // swap the two strings to consume less memory
    2544            final CharSequence tmp = s;
    2545            s = t;
    2546            t = tmp;
    2547            n = m;
    2548            m = t.length();
    2549        }
    2550
    2551        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
    2552        int[] d = new int[n + 1]; // cost array, horizontally
    2553        int[] tmp; // placeholder to assist in swapping p and d
    2554
    2555        // fill in starting table values
    2556        final int boundary = Math.min(n, threshold) + 1;
    2557        for (int i = 0; i < boundary; i++) {
    2558            p[i] = i;
    2559        }
    2560        // these fills ensure that the value above the rightmost entry of our
    2561        // stripe will be ignored in following loop iterations
    2562        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    2563        Arrays.fill(d, Integer.MAX_VALUE);
    2564
    2565        // iterates through t
    2566        for (int j = 1; j <= m; j++) {
    2567            final char jOfT = t.charAt(j - 1); // jth character of t
    2568            d[0] = j;
    2569
    2570            // compute stripe indices, constrain to array size
    2571            final int min = Math.max(1, j - threshold);
    2572            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
    2573
    2574            // the stripe may lead off of the table if s and t are of different sizes
    2575            if (min > max) {
    2576                return -1;
    2577            }
    2578
    2579            // ignore entry left of leftmost
    2580            if (min > 1) {
    2581                d[min - 1] = Integer.MAX_VALUE;
    2582            }
    2583
    2584            // iterates through [min, max] in s
    2585            for (int i = min; i <= max; i++) {
    2586                if (s.charAt(i - 1) == jOfT) {
    2587                    // diagonally left and up
    2588                    d[i] = p[i - 1];
    2589                } else {
    2590                    // 1 + minimum of cell to the left, to the top, diagonally left and up
    2591                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
    2592                }
    2593            }
    2594
    2595            // copy current distance counts to 'previous row' distance counts
    2596            tmp = p;
    2597            p = d;
    2598            d = tmp;
    2599        }
    2600
    2601        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    2602        // distance
    2603        if (p[n] <= threshold) {
    2604            return p[n];
    2605        }
    2606        return -1;
    2607    }
    2608
    2609    /**
    2610     * Finds the first index within a CharSequence, handling {@code null}.
    2611     * This method uses {@link String#indexOf(String, int)} if possible.
    2612     *
    2613     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    2614     *
    2615     * <pre>
    2616     * StringUtils.indexOf(null, *)          = -1
    2617     * StringUtils.indexOf(*, null)          = -1
    2618     * StringUtils.indexOf("", "")           = 0
    2619     * StringUtils.indexOf("", *)            = -1 (except when * = "")
    2620     * StringUtils.indexOf("aabaabaa", "a")  = 0
    2621     * StringUtils.indexOf("aabaabaa", "b")  = 2
    2622     * StringUtils.indexOf("aabaabaa", "ab") = 1
    2623     * StringUtils.indexOf("aabaabaa", "")   = 0
    2624     * </pre>
    2625     *
    2626     * @param seq  the CharSequence to check, may be null
    2627     * @param searchSeq  the CharSequence to find, may be null
    2628     * @return the first index of the search CharSequence,
    2629     *  -1 if no match or {@code null} string input
    2630     * @since 2.0
    2631     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
    2632     */
    2633    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
    2634        if (seq == null || searchSeq == null) {
    2635            return INDEX_NOT_FOUND;
    2636        }
    2637        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
    2638    }
    2639
    2640    /**
    2641     * Finds the first index within a CharSequence, handling {@code null}.
    2642     * This method uses {@link String#indexOf(String, int)} if possible.
    2643     *
    2644     * <p>A {@code null} CharSequence will return {@code -1}.
    2645     * A negative start position is treated as zero.
    2646     * An empty ("") search CharSequence always matches.
    2647     * A start position greater than the string length only matches
    2648     * an empty search CharSequence.</p>
    2649     *
    2650     * <pre>
    2651     * StringUtils.indexOf(null, *, *)          = -1
    2652     * StringUtils.indexOf(*, null, *)          = -1
    2653     * StringUtils.indexOf("", "", 0)           = 0
    2654     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    2655     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    2656     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    2657     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    2658     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    2659     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    2660     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    2661     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    2662     * StringUtils.indexOf("abc", "", 9)        = 3
    2663     * </pre>
    2664     *
    2665     * @param seq  the CharSequence to check, may be null
    2666     * @param searchSeq  the CharSequence to find, may be null
    2667     * @param startPos  the start position, negative treated as zero
    2668     * @return the first index of the search CharSequence (always &ge; startPos),
    2669     *  -1 if no match or {@code null} string input
    2670     * @since 2.0
    2671     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
    2672     */
    2673    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    2674        if (seq == null || searchSeq == null) {
    2675            return INDEX_NOT_FOUND;
    2676        }
    2677        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
    2678    }
    2679
    2680    /**
    2681     * Returns the index within {@code seq} of the first occurrence of
    2682     * the specified character. If a character with value
    2683     * {@code searchChar} occurs in the character sequence represented by
    2684     * {@code seq} {@link CharSequence} object, then the index (in Unicode
    2685     * code units) of the first such occurrence is returned. For
    2686     * values of {@code searchChar} in the range from 0 to 0xFFFF
    2687     * (inclusive), this is the smallest value <i>k</i> such that:
    2688     * <blockquote><pre>
    2689     * this.charAt(<i>k</i>) == searchChar
    2690     * </pre></blockquote>
    2691     * is true. For other values of {@code searchChar}, it is the
    2692     * smallest value <i>k</i> such that:
    2693     * <blockquote><pre>
    2694     * this.codePointAt(<i>k</i>) == searchChar
    2695     * </pre></blockquote>
    2696     * is true. In either case, if no such character occurs in {@code seq},
    2697     * then {@code INDEX_NOT_FOUND (-1)} is returned.
    2698     *
    2699     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
    2700     * return {@code INDEX_NOT_FOUND (-1)}.</p>
    2701     *
    2702     * <pre>
    2703     * StringUtils.indexOf(null, *)         = -1
    2704     * StringUtils.indexOf("", *)           = -1
    2705     * StringUtils.indexOf("aabaabaa", 'a') = 0
    2706     * StringUtils.indexOf("aabaabaa", 'b') = 2
    2707     * </pre>
    2708     *
    2709     * @param seq  the CharSequence to check, may be null
    2710     * @param searchChar  the character to find
    2711     * @return the first index of the search character,
    2712     *  -1 if no match or {@code null} string input
    2713     * @since 2.0
    2714     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
    2715     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2716     */
    2717    public static int indexOf(final CharSequence seq, final int searchChar) {
    2718        if (isEmpty(seq)) {
    2719            return INDEX_NOT_FOUND;
    2720        }
    2721        return CharSequenceUtils.indexOf(seq, searchChar, 0);
    2722    }
    2723
    2724    /**
    2725     * Returns the index within {@code seq} of the first occurrence of the
    2726     * specified character, starting the search at the specified index.
    2727     * <p>
    2728     * If a character with value {@code searchChar} occurs in the
    2729     * character sequence represented by the {@code seq} {@link CharSequence}
    2730     * object at an index no smaller than {@code startPos}, then
    2731     * the index of the first such occurrence is returned. For values
    2732     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
    2733     * this is the smallest value <i>k</i> such that:
    2734     * <blockquote><pre>
    2735     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    2736     * </pre></blockquote>
    2737     * is true. For other values of {@code searchChar}, it is the
    2738     * smallest value <i>k</i> such that:
    2739     * <blockquote><pre>
    2740     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    2741     * </pre></blockquote>
    2742     * is true. In either case, if no such character occurs in {@code seq}
    2743     * at or after position {@code startPos}, then
    2744     * {@code -1} is returned.
    2745     *
    2746     * <p>
    2747     * There is no restriction on the value of {@code startPos}. If it
    2748     * is negative, it has the same effect as if it were zero: this entire
    2749     * string may be searched. If it is greater than the length of this
    2750     * string, it has the same effect as if it were equal to the length of
    2751     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
    2752     * {@code null} or empty ("") CharSequence will
    2753     * return {@code (INDEX_NOT_FOUND) -1}.
    2754     *
    2755     * <p>All indices are specified in {@code char} values
    2756     * (Unicode code units).
    2757     *
    2758     * <pre>
    2759     * StringUtils.indexOf(null, *, *)          = -1
    2760     * StringUtils.indexOf("", *, *)            = -1
    2761     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    2762     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    2763     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    2764     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    2765     * </pre>
    2766     *
    2767     * @param seq  the CharSequence to check, may be null
    2768     * @param searchChar  the character to find
    2769     * @param startPos  the start position, negative treated as zero
    2770     * @return the first index of the search character (always &ge; startPos),
    2771     *  -1 if no match or {@code null} string input
    2772     * @since 2.0
    2773     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
    2774     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    2775     */
    2776    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
    2777        if (isEmpty(seq)) {
    2778            return INDEX_NOT_FOUND;
    2779        }
    2780        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
    2781    }
    2782
    2783    /**
    2784     * Search a CharSequence to find the first index of any
    2785     * character in the given set of characters.
    2786     *
    2787     * <p>A {@code null} String will return {@code -1}.
    2788     * A {@code null} or zero length search array will return {@code -1}.</p>
    2789     *
    2790     * <pre>
    2791     * StringUtils.indexOfAny(null, *)                  = -1
    2792     * StringUtils.indexOfAny("", *)                    = -1
    2793     * StringUtils.indexOfAny(*, null)                  = -1
    2794     * StringUtils.indexOfAny(*, [])                    = -1
    2795     * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
    2796     * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
    2797     * StringUtils.indexOfAny("aba", ['z'])             = -1
    2798     * </pre>
    2799     *
    2800     * @param cs  the CharSequence to check, may be null
    2801     * @param searchChars  the chars to search for, may be null
    2802     * @return the index of any of the chars, -1 if no match or null input
    2803     * @since 2.0
    2804     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2805     */
    2806    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    2807        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2808            return INDEX_NOT_FOUND;
    2809        }
    2810        final int csLen = cs.length();
    2811        final int csLast = csLen - 1;
    2812        final int searchLen = searchChars.length;
    2813        final int searchLast = searchLen - 1;
    2814        for (int i = 0; i < csLen; i++) {
    2815            final char ch = cs.charAt(i);
    2816            for (int j = 0; j < searchLen; j++) {
    2817                if (searchChars[j] == ch) {
    2818                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
    2819                        return i;
    2820                    }
    2821                    // ch is a supplementary character
    2822                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2823                        return i;
    2824                    }
    2825                }
    2826            }
    2827        }
    2828        return INDEX_NOT_FOUND;
    2829    }
    2830
    2831    /**
    2832     * Find the first index of any of a set of potential substrings.
    2833     *
    2834     * <p>A {@code null} CharSequence will return {@code -1}.
    2835     * A {@code null} or zero length search array will return {@code -1}.
    2836     * A {@code null} search array entry will be ignored, but a search
    2837     * array containing "" will return {@code 0} if {@code str} is not
    2838     * null. This method uses {@link String#indexOf(String)} if possible.</p>
    2839     *
    2840     * <pre>
    2841     * StringUtils.indexOfAny(null, *)                      = -1
    2842     * StringUtils.indexOfAny(*, null)                      = -1
    2843     * StringUtils.indexOfAny(*, [])                        = -1
    2844     * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
    2845     * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
    2846     * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
    2847     * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
    2848     * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
    2849     * StringUtils.indexOfAny("", [""])                     = 0
    2850     * StringUtils.indexOfAny("", ["a"])                    = -1
    2851     * </pre>
    2852     *
    2853     * @param str  the CharSequence to check, may be null
    2854     * @param searchStrs  the CharSequences to search for, may be null
    2855     * @return the first index of any of the searchStrs in str, -1 if no match
    2856     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
    2857     */
    2858    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2859        if (str == null || searchStrs == null) {
    2860            return INDEX_NOT_FOUND;
    2861        }
    2862
    2863        // String's can't have a MAX_VALUEth index.
    2864        int ret = Integer.MAX_VALUE;
    2865
    2866        int tmp;
    2867        for (final CharSequence search : searchStrs) {
    2868            if (search == null) {
    2869                continue;
    2870            }
    2871            tmp = CharSequenceUtils.indexOf(str, search, 0);
    2872            if (tmp == INDEX_NOT_FOUND) {
    2873                continue;
    2874            }
    2875
    2876            if (tmp < ret) {
    2877                ret = tmp;
    2878            }
    2879        }
    2880
    2881        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
    2882    }
    2883
    2884    /**
    2885     * Search a CharSequence to find the first index of any
    2886     * character in the given set of characters.
    2887     *
    2888     * <p>A {@code null} String will return {@code -1}.
    2889     * A {@code null} search string will return {@code -1}.</p>
    2890     *
    2891     * <pre>
    2892     * StringUtils.indexOfAny(null, *)            = -1
    2893     * StringUtils.indexOfAny("", *)              = -1
    2894     * StringUtils.indexOfAny(*, null)            = -1
    2895     * StringUtils.indexOfAny(*, "")              = -1
    2896     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    2897     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    2898     * StringUtils.indexOfAny("aba", "z")         = -1
    2899     * </pre>
    2900     *
    2901     * @param cs  the CharSequence to check, may be null
    2902     * @param searchChars  the chars to search for, may be null
    2903     * @return the index of any of the chars, -1 if no match or null input
    2904     * @since 2.0
    2905     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    2906     */
    2907    public static int indexOfAny(final CharSequence cs, final String searchChars) {
    2908        if (isEmpty(cs) || isEmpty(searchChars)) {
    2909            return INDEX_NOT_FOUND;
    2910        }
    2911        return indexOfAny(cs, searchChars.toCharArray());
    2912    }
    2913
    2914    /**
    2915     * Searches a CharSequence to find the first index of any
    2916     * character not in the given set of characters.
    2917     *
    2918     * <p>A {@code null} CharSequence will return {@code -1}.
    2919     * A {@code null} or zero length search array will return {@code -1}.</p>
    2920     *
    2921     * <pre>
    2922     * StringUtils.indexOfAnyBut(null, *)                              = -1
    2923     * StringUtils.indexOfAnyBut("", *)                                = -1
    2924     * StringUtils.indexOfAnyBut(*, null)                              = -1
    2925     * StringUtils.indexOfAnyBut(*, [])                                = -1
    2926     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
    2927     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
    2928     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
    2929
    2930     * </pre>
    2931     *
    2932     * @param cs  the CharSequence to check, may be null
    2933     * @param searchChars  the chars to search for, may be null
    2934     * @return the index of any of the chars, -1 if no match or null input
    2935     * @since 2.0
    2936     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
    2937     */
    2938    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    2939        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2940            return INDEX_NOT_FOUND;
    2941        }
    2942        final int csLen = cs.length();
    2943        final int csLast = csLen - 1;
    2944        final int searchLen = searchChars.length;
    2945        final int searchLast = searchLen - 1;
    2946        outer:
    2947        for (int i = 0; i < csLen; i++) {
    2948            final char ch = cs.charAt(i);
    2949            for (int j = 0; j < searchLen; j++) {
    2950                if (searchChars[j] == ch) {
    2951                    if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
    2952                        continue outer;
    2953                    }
    2954                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2955                        continue outer;
    2956                    }
    2957                }
    2958            }
    2959            return i;
    2960        }
    2961        return INDEX_NOT_FOUND;
    2962    }
    2963
    2964    /**
    2965     * Search a CharSequence to find the first index of any
    2966     * character not in the given set of characters.
    2967     *
    2968     * <p>A {@code null} CharSequence will return {@code -1}.
    2969     * A {@code null} or empty search string will return {@code -1}.</p>
    2970     *
    2971     * <pre>
    2972     * StringUtils.indexOfAnyBut(null, *)            = -1
    2973     * StringUtils.indexOfAnyBut("", *)              = -1
    2974     * StringUtils.indexOfAnyBut(*, null)            = -1
    2975     * StringUtils.indexOfAnyBut(*, "")              = -1
    2976     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    2977     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
    2978     * StringUtils.indexOfAnyBut("aba", "ab")        = -1
    2979     * </pre>
    2980     *
    2981     * @param seq  the CharSequence to check, may be null
    2982     * @param searchChars  the chars to search for, may be null
    2983     * @return the index of any of the chars, -1 if no match or null input
    2984     * @since 2.0
    2985     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
    2986     */
    2987    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
    2988        if (isEmpty(seq) || isEmpty(searchChars)) {
    2989            return INDEX_NOT_FOUND;
    2990        }
    2991        final int strLen = seq.length();
    2992        for (int i = 0; i < strLen; i++) {
    2993            final char ch = seq.charAt(i);
    2994            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
    2995            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
    2996                final char ch2 = seq.charAt(i + 1);
    2997                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
    2998                    return i;
    2999                }
    3000            } else if (!chFound) {
    3001                return i;
    3002            }
    3003        }
    3004        return INDEX_NOT_FOUND;
    3005    }
    3006
    3007    /**
    3008     * Compares all CharSequences in an array and returns the index at which the
    3009     * CharSequences begin to differ.
    3010     *
    3011     * <p>For example,
    3012     * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
    3013     *
    3014     * <pre>
    3015     * StringUtils.indexOfDifference(null)                             = -1
    3016     * StringUtils.indexOfDifference(new String[] {})                  = -1
    3017     * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
    3018     * StringUtils.indexOfDifference(new String[] {null, null})        = -1
    3019     * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
    3020     * StringUtils.indexOfDifference(new String[] {"", null})          = 0
    3021     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    3022     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    3023     * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
    3024     * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
    3025     * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
    3026     * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
    3027     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
    3028     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
    3029     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
    3030     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
    3031     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    3032     * </pre>
    3033     *
    3034     * @param css  array of CharSequences, entries may be null
    3035     * @return the index where the strings begin to differ; -1 if they are all equal
    3036     * @since 2.4
    3037     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    3038     */
    3039    public static int indexOfDifference(final CharSequence... css) {
    3040        if (ArrayUtils.getLength(css) <= 1) {
    3041            return INDEX_NOT_FOUND;
    3042        }
    3043        boolean anyStringNull = false;
    3044        boolean allStringsNull = true;
    3045        final int arrayLen = css.length;
    3046        int shortestStrLen = Integer.MAX_VALUE;
    3047        int longestStrLen = 0;
    3048
    3049        // find the min and max string lengths; this avoids checking to make
    3050        // sure we are not exceeding the length of the string each time through
    3051        // the bottom loop.
    3052        for (final CharSequence cs : css) {
    3053            if (cs == null) {
    3054                anyStringNull = true;
    3055                shortestStrLen = 0;
    3056            } else {
    3057                allStringsNull = false;
    3058                shortestStrLen = Math.min(cs.length(), shortestStrLen);
    3059                longestStrLen = Math.max(cs.length(), longestStrLen);
    3060            }
    3061        }
    3062
    3063        // handle lists containing all nulls or all empty strings
    3064        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
    3065            return INDEX_NOT_FOUND;
    3066        }
    3067
    3068        // handle lists containing some nulls or some empty strings
    3069        if (shortestStrLen == 0) {
    3070            return 0;
    3071        }
    3072
    3073        // find the position with the first difference across all strings
    3074        int firstDiff = -1;
    3075        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    3076            final char comparisonChar = css[0].charAt(stringPos);
    3077            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    3078                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    3079                    firstDiff = stringPos;
    3080                    break;
    3081                }
    3082            }
    3083            if (firstDiff != -1) {
    3084                break;
    3085            }
    3086        }
    3087
    3088        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    3089            // we compared all of the characters up to the length of the
    3090            // shortest string and didn't find a match, but the string lengths
    3091            // vary, so return the length of the shortest string.
    3092            return shortestStrLen;
    3093        }
    3094        return firstDiff;
    3095    }
    3096
    3097    /**
    3098     * Compares two CharSequences, and returns the index at which the
    3099     * CharSequences begin to differ.
    3100     *
    3101     * <p>For example,
    3102     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
    3103     *
    3104     * <pre>
    3105     * StringUtils.indexOfDifference(null, null)       = -1
    3106     * StringUtils.indexOfDifference("", "")           = -1
    3107     * StringUtils.indexOfDifference("", "abc")        = 0
    3108     * StringUtils.indexOfDifference("abc", "")        = 0
    3109     * StringUtils.indexOfDifference("abc", "abc")     = -1
    3110     * StringUtils.indexOfDifference("ab", "abxyz")    = 2
    3111     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    3112     * StringUtils.indexOfDifference("abcde", "xyz")   = 0
    3113     * </pre>
    3114     *
    3115     * @param cs1  the first CharSequence, may be null
    3116     * @param cs2  the second CharSequence, may be null
    3117     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
    3118     * @since 2.0
    3119     * @since 3.0 Changed signature from indexOfDifference(String, String) to
    3120     * indexOfDifference(CharSequence, CharSequence)
    3121     */
    3122    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
    3123        if (cs1 == cs2) {
    3124            return INDEX_NOT_FOUND;
    3125        }
    3126        if (cs1 == null || cs2 == null) {
    3127            return 0;
    3128        }
    3129        int i;
    3130        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    3131            if (cs1.charAt(i) != cs2.charAt(i)) {
    3132                break;
    3133            }
    3134        }
    3135        if (i < cs2.length() || i < cs1.length()) {
    3136            return i;
    3137        }
    3138        return INDEX_NOT_FOUND;
    3139    }
    3140
    3141    /**
    3142     * Case in-sensitive find of the first index within a CharSequence.
    3143     *
    3144     * <p>A {@code null} CharSequence will return {@code -1}.
    3145     * A negative start position is treated as zero.
    3146     * An empty ("") search CharSequence always matches.
    3147     * A start position greater than the string length only matches
    3148     * an empty search CharSequence.</p>
    3149     *
    3150     * <pre>
    3151     * StringUtils.indexOfIgnoreCase(null, *)          = -1
    3152     * StringUtils.indexOfIgnoreCase(*, null)          = -1
    3153     * StringUtils.indexOfIgnoreCase("", "")           = 0
    3154     * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
    3155     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    3156     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    3157     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    3158     * </pre>
    3159     *
    3160     * @param str  the CharSequence to check, may be null
    3161     * @param searchStr  the CharSequence to find, may be null
    3162     * @return the first index of the search CharSequence,
    3163     *  -1 if no match or {@code null} string input
    3164     * @since 2.5
    3165     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
    3166     */
    3167    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    3168        return indexOfIgnoreCase(str, searchStr, 0);
    3169    }
    3170
    3171    /**
    3172     * Case in-sensitive find of the first index within a CharSequence
    3173     * from the specified position.
    3174     *
    3175     * <p>A {@code null} CharSequence will return {@code -1}.
    3176     * A negative start position is treated as zero.
    3177     * An empty ("") search CharSequence always matches.
    3178     * A start position greater than the string length only matches
    3179     * an empty search CharSequence.</p>
    3180     *
    3181     * <pre>
    3182     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    3183     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    3184     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    3185     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    3186     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    3187     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    3188     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    3189     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    3190     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    3191     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    3192     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
    3193     * </pre>
    3194     *
    3195     * @param str  the CharSequence to check, may be null
    3196     * @param searchStr  the CharSequence to find, may be null
    3197     * @param startPos  the start position, negative treated as zero
    3198     * @return the first index of the search CharSequence (always &ge; startPos),
    3199     *  -1 if no match or {@code null} string input
    3200     * @since 2.5
    3201     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
    3202     */
    3203    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    3204        if (str == null || searchStr == null) {
    3205            return INDEX_NOT_FOUND;
    3206        }
    3207        if (startPos < 0) {
    3208            startPos = 0;
    3209        }
    3210        final int endLimit = str.length() - searchStr.length() + 1;
    3211        if (startPos > endLimit) {
    3212            return INDEX_NOT_FOUND;
    3213        }
    3214        if (searchStr.length() == 0) {
    3215            return startPos;
    3216        }
    3217        for (int i = startPos; i < endLimit; i++) {
    3218            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
    3219                return i;
    3220            }
    3221        }
    3222        return INDEX_NOT_FOUND;
    3223    }
    3224
    3225    /**
    3226     * Checks if all of the CharSequences are empty (""), null or whitespace only.
    3227     *
    3228     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3229     *
    3230     * <pre>
    3231     * StringUtils.isAllBlank(null)             = true
    3232     * StringUtils.isAllBlank(null, "foo")      = false
    3233     * StringUtils.isAllBlank(null, null)       = true
    3234     * StringUtils.isAllBlank("", "bar")        = false
    3235     * StringUtils.isAllBlank("bob", "")        = false
    3236     * StringUtils.isAllBlank("  bob  ", null)  = false
    3237     * StringUtils.isAllBlank(" ", "bar")       = false
    3238     * StringUtils.isAllBlank("foo", "bar")     = false
    3239     * StringUtils.isAllBlank(new String[] {})  = true
    3240     * </pre>
    3241     *
    3242     * @param css  the CharSequences to check, may be null or empty
    3243     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
    3244     * @since 3.6
    3245     */
    3246    public static boolean isAllBlank(final CharSequence... css) {
    3247        if (ArrayUtils.isEmpty(css)) {
    3248            return true;
    3249        }
    3250        for (final CharSequence cs : css) {
    3251            if (isNotBlank(cs)) {
    3252               return false;
    3253            }
    3254        }
    3255        return true;
    3256    }
    3257
    3258    /**
    3259     * Checks if all of the CharSequences are empty ("") or null.
    3260     *
    3261     * <pre>
    3262     * StringUtils.isAllEmpty(null)             = true
    3263     * StringUtils.isAllEmpty(null, "")         = true
    3264     * StringUtils.isAllEmpty(new String[] {})  = true
    3265     * StringUtils.isAllEmpty(null, "foo")      = false
    3266     * StringUtils.isAllEmpty("", "bar")        = false
    3267     * StringUtils.isAllEmpty("bob", "")        = false
    3268     * StringUtils.isAllEmpty("  bob  ", null)  = false
    3269     * StringUtils.isAllEmpty(" ", "bar")       = false
    3270     * StringUtils.isAllEmpty("foo", "bar")     = false
    3271     * </pre>
    3272     *
    3273     * @param css  the CharSequences to check, may be null or empty
    3274     * @return {@code true} if all of the CharSequences are empty or null
    3275     * @since 3.6
    3276     */
    3277    public static boolean isAllEmpty(final CharSequence... css) {
    3278        if (ArrayUtils.isEmpty(css)) {
    3279            return true;
    3280        }
    3281        for (final CharSequence cs : css) {
    3282            if (isNotEmpty(cs)) {
    3283                return false;
    3284            }
    3285        }
    3286        return true;
    3287    }
    3288
    3289    /**
    3290     * Checks if the CharSequence contains only lowercase characters.
    3291     *
    3292     * <p>{@code null} will return {@code false}.
    3293     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3294     *
    3295     * <pre>
    3296     * StringUtils.isAllLowerCase(null)   = false
    3297     * StringUtils.isAllLowerCase("")     = false
    3298     * StringUtils.isAllLowerCase("  ")   = false
    3299     * StringUtils.isAllLowerCase("abc")  = true
    3300     * StringUtils.isAllLowerCase("abC")  = false
    3301     * StringUtils.isAllLowerCase("ab c") = false
    3302     * StringUtils.isAllLowerCase("ab1c") = false
    3303     * StringUtils.isAllLowerCase("ab/c") = false
    3304     * </pre>
    3305     *
    3306     * @param cs  the CharSequence to check, may be null
    3307     * @return {@code true} if only contains lowercase characters, and is non-null
    3308     * @since 2.5
    3309     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    3310     */
    3311    public static boolean isAllLowerCase(final CharSequence cs) {
    3312        if (isEmpty(cs)) {
    3313            return false;
    3314        }
    3315        final int sz = cs.length();
    3316        for (int i = 0; i < sz; i++) {
    3317            if (!Character.isLowerCase(cs.charAt(i))) {
    3318                return false;
    3319            }
    3320        }
    3321        return true;
    3322    }
    3323
    3324    /**
    3325     * Checks if the CharSequence contains only uppercase characters.
    3326     *
    3327     * <p>{@code null} will return {@code false}.
    3328     * An empty String (length()=0) will return {@code false}.</p>
    3329     *
    3330     * <pre>
    3331     * StringUtils.isAllUpperCase(null)   = false
    3332     * StringUtils.isAllUpperCase("")     = false
    3333     * StringUtils.isAllUpperCase("  ")   = false
    3334     * StringUtils.isAllUpperCase("ABC")  = true
    3335     * StringUtils.isAllUpperCase("aBC")  = false
    3336     * StringUtils.isAllUpperCase("A C")  = false
    3337     * StringUtils.isAllUpperCase("A1C")  = false
    3338     * StringUtils.isAllUpperCase("A/C")  = false
    3339     * </pre>
    3340     *
    3341     * @param cs the CharSequence to check, may be null
    3342     * @return {@code true} if only contains uppercase characters, and is non-null
    3343     * @since 2.5
    3344     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    3345     */
    3346    public static boolean isAllUpperCase(final CharSequence cs) {
    3347        if (isEmpty(cs)) {
    3348            return false;
    3349        }
    3350        final int sz = cs.length();
    3351        for (int i = 0; i < sz; i++) {
    3352            if (!Character.isUpperCase(cs.charAt(i))) {
    3353                return false;
    3354            }
    3355        }
    3356        return true;
    3357    }
    3358
    3359    /**
    3360     * Checks if the CharSequence contains only Unicode letters.
    3361     *
    3362     * <p>{@code null} will return {@code false}.
    3363     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3364     *
    3365     * <pre>
    3366     * StringUtils.isAlpha(null)   = false
    3367     * StringUtils.isAlpha("")     = false
    3368     * StringUtils.isAlpha("  ")   = false
    3369     * StringUtils.isAlpha("abc")  = true
    3370     * StringUtils.isAlpha("ab2c") = false
    3371     * StringUtils.isAlpha("ab-c") = false
    3372     * </pre>
    3373     *
    3374     * @param cs  the CharSequence to check, may be null
    3375     * @return {@code true} if only contains letters, and is non-null
    3376     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    3377     * @since 3.0 Changed "" to return false and not true
    3378     */
    3379    public static boolean isAlpha(final CharSequence cs) {
    3380        if (isEmpty(cs)) {
    3381            return false;
    3382        }
    3383        final int sz = cs.length();
    3384        for (int i = 0; i < sz; i++) {
    3385            if (!Character.isLetter(cs.charAt(i))) {
    3386                return false;
    3387            }
    3388        }
    3389        return true;
    3390    }
    3391
    3392    /**
    3393     * Checks if the CharSequence contains only Unicode letters or digits.
    3394     *
    3395     * <p>{@code null} will return {@code false}.
    3396     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3397     *
    3398     * <pre>
    3399     * StringUtils.isAlphanumeric(null)   = false
    3400     * StringUtils.isAlphanumeric("")     = false
    3401     * StringUtils.isAlphanumeric("  ")   = false
    3402     * StringUtils.isAlphanumeric("abc")  = true
    3403     * StringUtils.isAlphanumeric("ab c") = false
    3404     * StringUtils.isAlphanumeric("ab2c") = true
    3405     * StringUtils.isAlphanumeric("ab-c") = false
    3406     * </pre>
    3407     *
    3408     * @param cs  the CharSequence to check, may be null
    3409     * @return {@code true} if only contains letters or digits,
    3410     *  and is non-null
    3411     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    3412     * @since 3.0 Changed "" to return false and not true
    3413     */
    3414    public static boolean isAlphanumeric(final CharSequence cs) {
    3415        if (isEmpty(cs)) {
    3416            return false;
    3417        }
    3418        final int sz = cs.length();
    3419        for (int i = 0; i < sz; i++) {
    3420            if (!Character.isLetterOrDigit(cs.charAt(i))) {
    3421                return false;
    3422            }
    3423        }
    3424        return true;
    3425    }
    3426
    3427    /**
    3428     * Checks if the CharSequence contains only Unicode letters, digits
    3429     * or space ({@code ' '}).
    3430     *
    3431     * <p>{@code null} will return {@code false}.
    3432     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3433     *
    3434     * <pre>
    3435     * StringUtils.isAlphanumericSpace(null)   = false
    3436     * StringUtils.isAlphanumericSpace("")     = true
    3437     * StringUtils.isAlphanumericSpace("  ")   = true
    3438     * StringUtils.isAlphanumericSpace("abc")  = true
    3439     * StringUtils.isAlphanumericSpace("ab c") = true
    3440     * StringUtils.isAlphanumericSpace("ab2c") = true
    3441     * StringUtils.isAlphanumericSpace("ab-c") = false
    3442     * </pre>
    3443     *
    3444     * @param cs  the CharSequence to check, may be null
    3445     * @return {@code true} if only contains letters, digits or space,
    3446     *  and is non-null
    3447     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    3448     */
    3449    public static boolean isAlphanumericSpace(final CharSequence cs) {
    3450        if (cs == null) {
    3451            return false;
    3452        }
    3453        final int sz = cs.length();
    3454        for (int i = 0; i < sz; i++) {
    3455            final char nowChar = cs.charAt(i);
    3456            if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) {
    3457                return false;
    3458            }
    3459        }
    3460        return true;
    3461    }
    3462
    3463    /**
    3464     * Checks if the CharSequence contains only Unicode letters and
    3465     * space (' ').
    3466     *
    3467     * <p>{@code null} will return {@code false}
    3468     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3469     *
    3470     * <pre>
    3471     * StringUtils.isAlphaSpace(null)   = false
    3472     * StringUtils.isAlphaSpace("")     = true
    3473     * StringUtils.isAlphaSpace("  ")   = true
    3474     * StringUtils.isAlphaSpace("abc")  = true
    3475     * StringUtils.isAlphaSpace("ab c") = true
    3476     * StringUtils.isAlphaSpace("ab2c") = false
    3477     * StringUtils.isAlphaSpace("ab-c") = false
    3478     * </pre>
    3479     *
    3480     * @param cs  the CharSequence to check, may be null
    3481     * @return {@code true} if only contains letters and space,
    3482     *  and is non-null
    3483     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    3484     */
    3485    public static boolean isAlphaSpace(final CharSequence cs) {
    3486        if (cs == null) {
    3487            return false;
    3488        }
    3489        final int sz = cs.length();
    3490        for (int i = 0; i < sz; i++) {
    3491            final char nowChar = cs.charAt(i);
    3492            if (nowChar != ' ' && !Character.isLetter(nowChar)) {
    3493                return false;
    3494            }
    3495        }
    3496        return true;
    3497    }
    3498
    3499    /**
    3500     * Checks if any of the CharSequences are empty ("") or null or whitespace only.
    3501     *
    3502     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3503     *
    3504     * <pre>
    3505     * StringUtils.isAnyBlank((String) null)    = true
    3506     * StringUtils.isAnyBlank((String[]) null)  = false
    3507     * StringUtils.isAnyBlank(null, "foo")      = true
    3508     * StringUtils.isAnyBlank(null, null)       = true
    3509     * StringUtils.isAnyBlank("", "bar")        = true
    3510     * StringUtils.isAnyBlank("bob", "")        = true
    3511     * StringUtils.isAnyBlank("  bob  ", null)  = true
    3512     * StringUtils.isAnyBlank(" ", "bar")       = true
    3513     * StringUtils.isAnyBlank(new String[] {})  = false
    3514     * StringUtils.isAnyBlank(new String[]{""}) = true
    3515     * StringUtils.isAnyBlank("foo", "bar")     = false
    3516     * </pre>
    3517     *
    3518     * @param css  the CharSequences to check, may be null or empty
    3519     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
    3520     * @since 3.2
    3521     */
    3522    public static boolean isAnyBlank(final CharSequence... css) {
    3523        if (ArrayUtils.isEmpty(css)) {
    3524            return false;
    3525        }
    3526        for (final CharSequence cs : css) {
    3527            if (isBlank(cs)) {
    3528                return true;
    3529            }
    3530        }
    3531        return false;
    3532    }
    3533
    3534    /**
    3535     * Checks if any of the CharSequences are empty ("") or null.
    3536     *
    3537     * <pre>
    3538     * StringUtils.isAnyEmpty((String) null)    = true
    3539     * StringUtils.isAnyEmpty((String[]) null)  = false
    3540     * StringUtils.isAnyEmpty(null, "foo")      = true
    3541     * StringUtils.isAnyEmpty("", "bar")        = true
    3542     * StringUtils.isAnyEmpty("bob", "")        = true
    3543     * StringUtils.isAnyEmpty("  bob  ", null)  = true
    3544     * StringUtils.isAnyEmpty(" ", "bar")       = false
    3545     * StringUtils.isAnyEmpty("foo", "bar")     = false
    3546     * StringUtils.isAnyEmpty(new String[]{})   = false
    3547     * StringUtils.isAnyEmpty(new String[]{""}) = true
    3548     * </pre>
    3549     *
    3550     * @param css  the CharSequences to check, may be null or empty
    3551     * @return {@code true} if any of the CharSequences are empty or null
    3552     * @since 3.2
    3553     */
    3554    public static boolean isAnyEmpty(final CharSequence... css) {
    3555        if (ArrayUtils.isEmpty(css)) {
    3556            return false;
    3557        }
    3558        for (final CharSequence cs : css) {
    3559            if (isEmpty(cs)) {
    3560                return true;
    3561            }
    3562        }
    3563        return false;
    3564    }
    3565
    3566    /**
    3567     * Checks if the CharSequence contains only ASCII printable characters.
    3568     *
    3569     * <p>{@code null} will return {@code false}.
    3570     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3571     *
    3572     * <pre>
    3573     * StringUtils.isAsciiPrintable(null)     = false
    3574     * StringUtils.isAsciiPrintable("")       = true
    3575     * StringUtils.isAsciiPrintable(" ")      = true
    3576     * StringUtils.isAsciiPrintable("Ceki")   = true
    3577     * StringUtils.isAsciiPrintable("ab2c")   = true
    3578     * StringUtils.isAsciiPrintable("!ab-c~") = true
    3579     * StringUtils.isAsciiPrintable("\u0020") = true
    3580     * StringUtils.isAsciiPrintable("\u0021") = true
    3581     * StringUtils.isAsciiPrintable("\u007e") = true
    3582     * StringUtils.isAsciiPrintable("\u007f") = false
    3583     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    3584     * </pre>
    3585     *
    3586     * @param cs the CharSequence to check, may be null
    3587     * @return {@code true} if every character is in the range
    3588     *  32 through 126
    3589     * @since 2.1
    3590     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    3591     */
    3592    public static boolean isAsciiPrintable(final CharSequence cs) {
    3593        if (cs == null) {
    3594            return false;
    3595        }
    3596        final int sz = cs.length();
    3597        for (int i = 0; i < sz; i++) {
    3598            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
    3599                return false;
    3600            }
    3601        }
    3602        return true;
    3603    }
    3604
    3605    /**
    3606     * Checks if a CharSequence is empty (""), null or whitespace only.
    3607     *
    3608     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3609     *
    3610     * <pre>
    3611     * StringUtils.isBlank(null)      = true
    3612     * StringUtils.isBlank("")        = true
    3613     * StringUtils.isBlank(" ")       = true
    3614     * StringUtils.isBlank("bob")     = false
    3615     * StringUtils.isBlank("  bob  ") = false
    3616     * </pre>
    3617     *
    3618     * @param cs  the CharSequence to check, may be null
    3619     * @return {@code true} if the CharSequence is null, empty or whitespace only
    3620     * @since 2.0
    3621     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    3622     */
    3623    public static boolean isBlank(final CharSequence cs) {
    3624        final int strLen = length(cs);
    3625        if (strLen == 0) {
    3626            return true;
    3627        }
    3628        for (int i = 0; i < strLen; i++) {
    3629            if (!Character.isWhitespace(cs.charAt(i))) {
    3630                return false;
    3631            }
    3632        }
    3633        return true;
    3634    }
    3635
    3636    /**
    3637     * Checks if a CharSequence is empty ("") or null.
    3638     *
    3639     * <pre>
    3640     * StringUtils.isEmpty(null)      = true
    3641     * StringUtils.isEmpty("")        = true
    3642     * StringUtils.isEmpty(" ")       = false
    3643     * StringUtils.isEmpty("bob")     = false
    3644     * StringUtils.isEmpty("  bob  ") = false
    3645     * </pre>
    3646     *
    3647     * <p>NOTE: This method changed in Lang version 2.0.
    3648     * It no longer trims the CharSequence.
    3649     * That functionality is available in isBlank().</p>
    3650     *
    3651     * @param cs  the CharSequence to check, may be null
    3652     * @return {@code true} if the CharSequence is empty or null
    3653     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    3654     */
    3655    public static boolean isEmpty(final CharSequence cs) {
    3656        return cs == null || cs.length() == 0;
    3657    }
    3658
    3659    /**
    3660     * Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.
    3661     *
    3662     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
    3663     * {@code false}.</p>
    3664     *
    3665     * <pre>
    3666     * StringUtils.isMixedCase(null)    = false
    3667     * StringUtils.isMixedCase("")      = false
    3668     * StringUtils.isMixedCase(" ")     = false
    3669     * StringUtils.isMixedCase("ABC")   = false
    3670     * StringUtils.isMixedCase("abc")   = false
    3671     * StringUtils.isMixedCase("aBc")   = true
    3672     * StringUtils.isMixedCase("A c")   = true
    3673     * StringUtils.isMixedCase("A1c")   = true
    3674     * StringUtils.isMixedCase("a/C")   = true
    3675     * StringUtils.isMixedCase("aC\t")  = true
    3676     * </pre>
    3677     *
    3678     * @param cs the CharSequence to check, may be null
    3679     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
    3680     * @since 3.5
    3681     */
    3682    public static boolean isMixedCase(final CharSequence cs) {
    3683        if (isEmpty(cs) || cs.length() == 1) {
    3684            return false;
    3685        }
    3686        boolean containsUppercase = false;
    3687        boolean containsLowercase = false;
    3688        final int sz = cs.length();
    3689        for (int i = 0; i < sz; i++) {
    3690            final char nowChar = cs.charAt(i);
    3691            if (Character.isUpperCase(nowChar)) {
    3692                containsUppercase = true;
    3693            } else if (Character.isLowerCase(nowChar)) {
    3694                containsLowercase = true;
    3695            }
    3696            if (containsUppercase && containsLowercase) {
    3697                return true;
    3698            }
    3699        }
    3700        return false;
    3701    }
    3702
    3703    /**
    3704     * Checks if none of the CharSequences are empty (""), null or whitespace only.
    3705     *
    3706     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3707     *
    3708     * <pre>
    3709     * StringUtils.isNoneBlank((String) null)    = false
    3710     * StringUtils.isNoneBlank((String[]) null)  = true
    3711     * StringUtils.isNoneBlank(null, "foo")      = false
    3712     * StringUtils.isNoneBlank(null, null)       = false
    3713     * StringUtils.isNoneBlank("", "bar")        = false
    3714     * StringUtils.isNoneBlank("bob", "")        = false
    3715     * StringUtils.isNoneBlank("  bob  ", null)  = false
    3716     * StringUtils.isNoneBlank(" ", "bar")       = false
    3717     * StringUtils.isNoneBlank(new String[] {})  = true
    3718     * StringUtils.isNoneBlank(new String[]{""}) = false
    3719     * StringUtils.isNoneBlank("foo", "bar")     = true
    3720     * </pre>
    3721     *
    3722     * @param css  the CharSequences to check, may be null or empty
    3723     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
    3724     * @since 3.2
    3725     */
    3726    public static boolean isNoneBlank(final CharSequence... css) {
    3727      return !isAnyBlank(css);
    3728    }
    3729
    3730    /**
    3731     * Checks if none of the CharSequences are empty ("") or null.
    3732     *
    3733     * <pre>
    3734     * StringUtils.isNoneEmpty((String) null)    = false
    3735     * StringUtils.isNoneEmpty((String[]) null)  = true
    3736     * StringUtils.isNoneEmpty(null, "foo")      = false
    3737     * StringUtils.isNoneEmpty("", "bar")        = false
    3738     * StringUtils.isNoneEmpty("bob", "")        = false
    3739     * StringUtils.isNoneEmpty("  bob  ", null)  = false
    3740     * StringUtils.isNoneEmpty(new String[] {})  = true
    3741     * StringUtils.isNoneEmpty(new String[]{""}) = false
    3742     * StringUtils.isNoneEmpty(" ", "bar")       = true
    3743     * StringUtils.isNoneEmpty("foo", "bar")     = true
    3744     * </pre>
    3745     *
    3746     * @param css  the CharSequences to check, may be null or empty
    3747     * @return {@code true} if none of the CharSequences are empty or null
    3748     * @since 3.2
    3749     */
    3750    public static boolean isNoneEmpty(final CharSequence... css) {
    3751      return !isAnyEmpty(css);
    3752    }
    3753
    3754    /**
    3755     * Checks if a CharSequence is not empty (""), not null and not whitespace only.
    3756     *
    3757     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3758     *
    3759     * <pre>
    3760     * StringUtils.isNotBlank(null)      = false
    3761     * StringUtils.isNotBlank("")        = false
    3762     * StringUtils.isNotBlank(" ")       = false
    3763     * StringUtils.isNotBlank("bob")     = true
    3764     * StringUtils.isNotBlank("  bob  ") = true
    3765     * </pre>
    3766     *
    3767     * @param cs  the CharSequence to check, may be null
    3768     * @return {@code true} if the CharSequence is
    3769     *  not empty and not null and not whitespace only
    3770     * @since 2.0
    3771     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    3772     */
    3773    public static boolean isNotBlank(final CharSequence cs) {
    3774        return !isBlank(cs);
    3775    }
    3776
    3777    /**
    3778     * Checks if a CharSequence is not empty ("") and not null.
    3779     *
    3780     * <pre>
    3781     * StringUtils.isNotEmpty(null)      = false
    3782     * StringUtils.isNotEmpty("")        = false
    3783     * StringUtils.isNotEmpty(" ")       = true
    3784     * StringUtils.isNotEmpty("bob")     = true
    3785     * StringUtils.isNotEmpty("  bob  ") = true
    3786     * </pre>
    3787     *
    3788     * @param cs  the CharSequence to check, may be null
    3789     * @return {@code true} if the CharSequence is not empty and not null
    3790     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    3791     */
    3792    public static boolean isNotEmpty(final CharSequence cs) {
    3793        return !isEmpty(cs);
    3794    }
    3795
    3796    /**
    3797     * Checks if the CharSequence contains only Unicode digits.
    3798     * A decimal point is not a Unicode digit and returns false.
    3799     *
    3800     * <p>{@code null} will return {@code false}.
    3801     * An empty CharSequence (length()=0) will return {@code false}.</p>
    3802     *
    3803     * <p>Note that the method does not allow for a leading sign, either positive or negative.
    3804     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
    3805     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
    3806     * for int or long respectively.</p>
    3807     *
    3808     * <pre>
    3809     * StringUtils.isNumeric(null)   = false
    3810     * StringUtils.isNumeric("")     = false
    3811     * StringUtils.isNumeric("  ")   = false
    3812     * StringUtils.isNumeric("123")  = true
    3813     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    3814     * StringUtils.isNumeric("12 3") = false
    3815     * StringUtils.isNumeric("ab2c") = false
    3816     * StringUtils.isNumeric("12-3") = false
    3817     * StringUtils.isNumeric("12.3") = false
    3818     * StringUtils.isNumeric("-123") = false
    3819     * StringUtils.isNumeric("+123") = false
    3820     * </pre>
    3821     *
    3822     * @param cs  the CharSequence to check, may be null
    3823     * @return {@code true} if only contains digits, and is non-null
    3824     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    3825     * @since 3.0 Changed "" to return false and not true
    3826     */
    3827    public static boolean isNumeric(final CharSequence cs) {
    3828        if (isEmpty(cs)) {
    3829            return false;
    3830        }
    3831        final int sz = cs.length();
    3832        for (int i = 0; i < sz; i++) {
    3833            if (!Character.isDigit(cs.charAt(i))) {
    3834                return false;
    3835            }
    3836        }
    3837        return true;
    3838    }
    3839
    3840    /**
    3841     * Checks if the CharSequence contains only Unicode digits or space
    3842     * ({@code ' '}).
    3843     * A decimal point is not a Unicode digit and returns false.
    3844     *
    3845     * <p>{@code null} will return {@code false}.
    3846     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3847     *
    3848     * <pre>
    3849     * StringUtils.isNumericSpace(null)   = false
    3850     * StringUtils.isNumericSpace("")     = true
    3851     * StringUtils.isNumericSpace("  ")   = true
    3852     * StringUtils.isNumericSpace("123")  = true
    3853     * StringUtils.isNumericSpace("12 3") = true
    3854     * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
    3855     * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
    3856     * StringUtils.isNumericSpace("ab2c") = false
    3857     * StringUtils.isNumericSpace("12-3") = false
    3858     * StringUtils.isNumericSpace("12.3") = false
    3859     * </pre>
    3860     *
    3861     * @param cs  the CharSequence to check, may be null
    3862     * @return {@code true} if only contains digits or space,
    3863     *  and is non-null
    3864     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    3865     */
    3866    public static boolean isNumericSpace(final CharSequence cs) {
    3867        if (cs == null) {
    3868            return false;
    3869        }
    3870        final int sz = cs.length();
    3871        for (int i = 0; i < sz; i++) {
    3872            final char nowChar = cs.charAt(i);
    3873            if (nowChar != ' ' && !Character.isDigit(nowChar)) {
    3874                return false;
    3875            }
    3876        }
    3877        return true;
    3878    }
    3879
    3880    /**
    3881     * Checks if the CharSequence contains only whitespace.
    3882     *
    3883     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3884     *
    3885     * <p>{@code null} will return {@code false}.
    3886     * An empty CharSequence (length()=0) will return {@code true}.</p>
    3887     *
    3888     * <pre>
    3889     * StringUtils.isWhitespace(null)   = false
    3890     * StringUtils.isWhitespace("")     = true
    3891     * StringUtils.isWhitespace("  ")   = true
    3892     * StringUtils.isWhitespace("abc")  = false
    3893     * StringUtils.isWhitespace("ab2c") = false
    3894     * StringUtils.isWhitespace("ab-c") = false
    3895     * </pre>
    3896     *
    3897     * @param cs  the CharSequence to check, may be null
    3898     * @return {@code true} if only contains whitespace, and is non-null
    3899     * @since 2.0
    3900     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    3901     */
    3902    public static boolean isWhitespace(final CharSequence cs) {
    3903        if (cs == null) {
    3904            return false;
    3905        }
    3906        final int sz = cs.length();
    3907        for (int i = 0; i < sz; i++) {
    3908            if (!Character.isWhitespace(cs.charAt(i))) {
    3909                return false;
    3910            }
    3911        }
    3912        return true;
    3913    }
    3914
    3915    /**
    3916     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3917     *
    3918     * <p>
    3919     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3920     * by empty strings.
    3921     * </p>
    3922     *
    3923     * <pre>
    3924     * StringUtils.join(null, *)             = null
    3925     * StringUtils.join([], *)               = ""
    3926     * StringUtils.join([null], *)           = ""
    3927     * StringUtils.join([false, false], ';') = "false;false"
    3928     * </pre>
    3929     *
    3930     * @param array
    3931     *            the array of values to join together, may be null
    3932     * @param delimiter
    3933     *            the separator character to use
    3934     * @return the joined String, {@code null} if null array input
    3935     * @since 3.12.0
    3936     */
    3937    public static String join(final boolean[] array, final char delimiter) {
    3938        if (array == null) {
    3939            return null;
    3940        }
    3941        return join(array, delimiter, 0, array.length);
    3942    }
    3943
    3944    /**
    3945     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3946     *
    3947     * <p>
    3948     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3949     * by empty strings.
    3950     * </p>
    3951     *
    3952     * <pre>
    3953     * StringUtils.join(null, *)                  = null
    3954     * StringUtils.join([], *)                    = ""
    3955     * StringUtils.join([null], *)                = ""
    3956     * StringUtils.join([true, false, true], ';') = "true;false;true"
    3957     * </pre>
    3958     *
    3959     * @param array
    3960     *            the array of values to join together, may be null
    3961     * @param delimiter
    3962     *            the separator character to use
    3963     * @param startIndex
    3964     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    3965     *            array
    3966     * @param endIndex
    3967     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    3968     *            the array
    3969     * @return the joined String, {@code null} if null array input
    3970     * @since 3.12.0
    3971     */
    3972    public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
    3973        if (array == null) {
    3974            return null;
    3975        }
    3976        if (endIndex - startIndex <= 0) {
    3977            return EMPTY;
    3978        }
    3979        final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
    3980        for (int i = startIndex; i < endIndex; i++) {
    3981            stringBuilder
    3982                    .append(array[i])
    3983                    .append(delimiter);
    3984        }
    3985        return stringBuilder.substring(0, stringBuilder.length() - 1);
    3986    }
    3987
    3988    /**
    3989     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3990     *
    3991     * <p>
    3992     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3993     * by empty strings.
    3994     * </p>
    3995     *
    3996     * <pre>
    3997     * StringUtils.join(null, *)         = null
    3998     * StringUtils.join([], *)           = ""
    3999     * StringUtils.join([null], *)       = ""
    4000     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4001     * StringUtils.join([1, 2, 3], null) = "123"
    4002     * </pre>
    4003     *
    4004     * @param array
    4005     *            the array of values to join together, may be null
    4006     * @param delimiter
    4007     *            the separator character to use
    4008     * @return the joined String, {@code null} if null array input
    4009     * @since 3.2
    4010     */
    4011    public static String join(final byte[] array, final char delimiter) {
    4012        if (array == null) {
    4013            return null;
    4014        }
    4015        return join(array, delimiter, 0, array.length);
    4016    }
    4017
    4018    /**
    4019     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4020     *
    4021     * <p>
    4022     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4023     * by empty strings.
    4024     * </p>
    4025     *
    4026     * <pre>
    4027     * StringUtils.join(null, *)         = null
    4028     * StringUtils.join([], *)           = ""
    4029     * StringUtils.join([null], *)       = ""
    4030     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4031     * StringUtils.join([1, 2, 3], null) = "123"
    4032     * </pre>
    4033     *
    4034     * @param array
    4035     *            the array of values to join together, may be null
    4036     * @param delimiter
    4037     *            the separator character to use
    4038     * @param startIndex
    4039     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4040     *            array
    4041     * @param endIndex
    4042     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4043     *            the array
    4044     * @return the joined String, {@code null} if null array input
    4045     * @since 3.2
    4046     */
    4047    public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
    4048        if (array == null) {
    4049            return null;
    4050        }
    4051        if (endIndex - startIndex <= 0) {
    4052            return EMPTY;
    4053        }
    4054        final StringBuilder stringBuilder = new StringBuilder();
    4055        for (int i = startIndex; i < endIndex; i++) {
    4056            stringBuilder
    4057                    .append(array[i])
    4058                    .append(delimiter);
    4059        }
    4060        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4061    }
    4062
    4063    /**
    4064     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4065     *
    4066     * <p>
    4067     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4068     * by empty strings.
    4069     * </p>
    4070     *
    4071     * <pre>
    4072     * StringUtils.join(null, *)         = null
    4073     * StringUtils.join([], *)           = ""
    4074     * StringUtils.join([null], *)       = ""
    4075     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4076     * StringUtils.join([1, 2, 3], null) = "123"
    4077     * </pre>
    4078     *
    4079     * @param array
    4080     *            the array of values to join together, may be null
    4081     * @param delimiter
    4082     *            the separator character to use
    4083     * @return the joined String, {@code null} if null array input
    4084     * @since 3.2
    4085     */
    4086    public static String join(final char[] array, final char delimiter) {
    4087        if (array == null) {
    4088            return null;
    4089        }
    4090        return join(array, delimiter, 0, array.length);
    4091    }
    4092
    4093    /**
    4094     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4095     *
    4096     * <p>
    4097     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4098     * by empty strings.
    4099     * </p>
    4100     *
    4101     * <pre>
    4102     * StringUtils.join(null, *)         = null
    4103     * StringUtils.join([], *)           = ""
    4104     * StringUtils.join([null], *)       = ""
    4105     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4106     * StringUtils.join([1, 2, 3], null) = "123"
    4107     * </pre>
    4108     *
    4109     * @param array
    4110     *            the array of values to join together, may be null
    4111     * @param delimiter
    4112     *            the separator character to use
    4113     * @param startIndex
    4114     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4115     *            array
    4116     * @param endIndex
    4117     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4118     *            the array
    4119     * @return the joined String, {@code null} if null array input
    4120     * @since 3.2
    4121     */
    4122    public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
    4123        if (array == null) {
    4124            return null;
    4125        }
    4126        if (endIndex - startIndex <= 0) {
    4127            return EMPTY;
    4128        }
    4129        final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
    4130        for (int i = startIndex; i < endIndex; i++) {
    4131            stringBuilder
    4132                    .append(array[i])
    4133                    .append(delimiter);
    4134        }
    4135        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4136    }
    4137
    4138    /**
    4139     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4140     *
    4141     * <p>
    4142     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4143     * by empty strings.
    4144     * </p>
    4145     *
    4146     * <pre>
    4147     * StringUtils.join(null, *)               = null
    4148     * StringUtils.join([], *)                 = ""
    4149     * StringUtils.join([null], *)             = ""
    4150     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4151     * StringUtils.join([1, 2, 3], null) = "123"
    4152     * </pre>
    4153     *
    4154     * @param array
    4155     *            the array of values to join together, may be null
    4156     * @param delimiter
    4157     *            the separator character to use
    4158     * @return the joined String, {@code null} if null array input
    4159     * @since 3.2
    4160     */
    4161    public static String join(final double[] array, final char delimiter) {
    4162        if (array == null) {
    4163            return null;
    4164        }
    4165        return join(array, delimiter, 0, array.length);
    4166    }
    4167
    4168    /**
    4169     * Joins the elements of the provided array into a single String containing the provided list of elements.
    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     * @param startIndex
    4189     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4190     *            array
    4191     * @param endIndex
    4192     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4193     *            the array
    4194     * @return the joined String, {@code null} if null array input
    4195     * @since 3.2
    4196     */
    4197    public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
    4198        if (array == null) {
    4199            return null;
    4200        }
    4201        if (endIndex - startIndex <= 0) {
    4202            return EMPTY;
    4203        }
    4204        final StringBuilder stringBuilder = new StringBuilder();
    4205        for (int i = startIndex; i < endIndex; i++) {
    4206            stringBuilder
    4207                    .append(array[i])
    4208                    .append(delimiter);
    4209        }
    4210        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4211    }
    4212
    4213    /**
    4214     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4215     *
    4216     * <p>
    4217     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4218     * by empty strings.
    4219     * </p>
    4220     *
    4221     * <pre>
    4222     * StringUtils.join(null, *)               = null
    4223     * StringUtils.join([], *)                 = ""
    4224     * StringUtils.join([null], *)             = ""
    4225     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4226     * StringUtils.join([1, 2, 3], null) = "123"
    4227     * </pre>
    4228     *
    4229     * @param array
    4230     *            the array of values to join together, may be null
    4231     * @param delimiter
    4232     *            the separator character to use
    4233     * @return the joined String, {@code null} if null array input
    4234     * @since 3.2
    4235     */
    4236    public static String join(final float[] array, final char delimiter) {
    4237        if (array == null) {
    4238            return null;
    4239        }
    4240        return join(array, delimiter, 0, array.length);
    4241    }
    4242
    4243    /**
    4244     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4245     *
    4246     * <p>
    4247     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4248     * by empty strings.
    4249     * </p>
    4250     *
    4251     * <pre>
    4252     * StringUtils.join(null, *)               = null
    4253     * StringUtils.join([], *)                 = ""
    4254     * StringUtils.join([null], *)             = ""
    4255     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4256     * StringUtils.join([1, 2, 3], null) = "123"
    4257     * </pre>
    4258     *
    4259     * @param array
    4260     *            the array of values to join together, may be null
    4261     * @param delimiter
    4262     *            the separator character to use
    4263     * @param startIndex
    4264     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4265     *            array
    4266     * @param endIndex
    4267     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4268     *            the array
    4269     * @return the joined String, {@code null} if null array input
    4270     * @since 3.2
    4271     */
    4272    public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
    4273        if (array == null) {
    4274            return null;
    4275        }
    4276        if (endIndex - startIndex <= 0) {
    4277            return EMPTY;
    4278        }
    4279        final StringBuilder stringBuilder = new StringBuilder();
    4280        for (int i = startIndex; i < endIndex; i++) {
    4281            stringBuilder
    4282                    .append(array[i])
    4283                    .append(delimiter);
    4284        }
    4285        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4286    }
    4287
    4288    /**
    4289     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4290     *
    4291     * <p>
    4292     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4293     * by empty strings.
    4294     * </p>
    4295     *
    4296     * <pre>
    4297     * StringUtils.join(null, *)               = null
    4298     * StringUtils.join([], *)                 = ""
    4299     * StringUtils.join([null], *)             = ""
    4300     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4301     * StringUtils.join([1, 2, 3], null) = "123"
    4302     * </pre>
    4303     *
    4304     * @param array
    4305     *            the array of values to join together, may be null
    4306     * @param separator
    4307     *            the separator character to use
    4308     * @return the joined String, {@code null} if null array input
    4309     * @since 3.2
    4310     */
    4311    public static String join(final int[] array, final char separator) {
    4312        if (array == null) {
    4313            return null;
    4314        }
    4315        return join(array, separator, 0, array.length);
    4316    }
    4317
    4318    /**
    4319     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4320     *
    4321     * <p>
    4322     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4323     * by empty strings.
    4324     * </p>
    4325     *
    4326     * <pre>
    4327     * StringUtils.join(null, *)               = null
    4328     * StringUtils.join([], *)                 = ""
    4329     * StringUtils.join([null], *)             = ""
    4330     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4331     * StringUtils.join([1, 2, 3], null) = "123"
    4332     * </pre>
    4333     *
    4334     * @param array
    4335     *            the array of values to join together, may be null
    4336     * @param delimiter
    4337     *            the separator character to use
    4338     * @param startIndex
    4339     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4340     *            array
    4341     * @param endIndex
    4342     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4343     *            the array
    4344     * @return the joined String, {@code null} if null array input
    4345     * @since 3.2
    4346     */
    4347    public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
    4348        if (array == null) {
    4349            return null;
    4350        }
    4351        if (endIndex - startIndex <= 0) {
    4352            return EMPTY;
    4353        }
    4354        final StringBuilder stringBuilder = new StringBuilder();
    4355        for (int i = startIndex; i < endIndex; i++) {
    4356            stringBuilder
    4357                    .append(array[i])
    4358                    .append(delimiter);
    4359        }
    4360        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4361    }
    4362
    4363    /**
    4364     * Joins the elements of the provided {@link Iterable} into
    4365     * a single String containing the provided elements.
    4366     *
    4367     * <p>No delimiter is added before or after the list. Null objects or empty
    4368     * strings within the iteration are represented by empty strings.</p>
    4369     *
    4370     * <p>See the examples here: {@link #join(Object[],char)}.</p>
    4371     *
    4372     * @param iterable  the {@link Iterable} providing the values to join together, may be null
    4373     * @param separator  the separator character to use
    4374     * @return the joined String, {@code null} if null iterator input
    4375     * @since 2.3
    4376     */
    4377    public static String join(final Iterable<?> iterable, final char separator) {
    4378        return iterable != null ? join(iterable.iterator(), separator) : null;
    4379    }
    4380
    4381    /**
    4382     * Joins the elements of the provided {@link Iterable} into
    4383     * a single String containing the provided elements.
    4384     *
    4385     * <p>No delimiter is added before or after the list.
    4386     * A {@code null} separator is the same as an empty String ("").</p>
    4387     *
    4388     * <p>See the examples here: {@link #join(Object[],String)}.</p>
    4389     *
    4390     * @param iterable  the {@link Iterable} providing the values to join together, may be null
    4391     * @param separator  the separator character to use, null treated as ""
    4392     * @return the joined String, {@code null} if null iterator input
    4393     * @since 2.3
    4394     */
    4395    public static String join(final Iterable<?> iterable, final String separator) {
    4396        return iterable != null ? join(iterable.iterator(), separator) : null;
    4397    }
    4398
    4399    /**
    4400     * Joins the elements of the provided {@link Iterator} into
    4401     * a single String containing the provided elements.
    4402     *
    4403     * <p>No delimiter is added before or after the list. Null objects or empty
    4404     * strings within the iteration are represented by empty strings.</p>
    4405     *
    4406     * <p>See the examples here: {@link #join(Object[],char)}.</p>
    4407     *
    4408     * @param iterator  the {@link Iterator} of values to join together, may be null
    4409     * @param separator  the separator character to use
    4410     * @return the joined String, {@code null} if null iterator input
    4411     * @since 2.0
    4412     */
    4413    public static String join(final Iterator<?> iterator, final char separator) {
    4414        // handle null, zero and one elements before building a buffer
    4415        if (iterator == null) {
    4416            return null;
    4417        }
    4418        if (!iterator.hasNext()) {
    4419            return EMPTY;
    4420        }
    4421        return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(String.valueOf(separator)), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
    4422    }
    4423
    4424    /**
    4425     * Joins the elements of the provided {@link Iterator} into
    4426     * a single String containing the provided elements.
    4427     *
    4428     * <p>No delimiter is added before or after the list.
    4429     * A {@code null} separator is the same as an empty String ("").</p>
    4430     *
    4431     * <p>See the examples here: {@link #join(Object[],String)}.</p>
    4432     *
    4433     * @param iterator  the {@link Iterator} of values to join together, may be null
    4434     * @param separator  the separator character to use, null treated as ""
    4435     * @return the joined String, {@code null} if null iterator input
    4436     */
    4437    public static String join(final Iterator<?> iterator, final String separator) {
    4438        // handle null, zero and one elements before building a buffer
    4439        if (iterator == null) {
    4440            return null;
    4441        }
    4442        if (!iterator.hasNext()) {
    4443            return EMPTY;
    4444        }
    4445        return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(separator), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
    4446    }
    4447
    4448    /**
    4449     * Joins the elements of the provided {@link List} into a single String
    4450     * containing the provided list of elements.
    4451     *
    4452     * <p>No delimiter is added before or after the list.
    4453     * Null objects or empty strings within the array are represented by
    4454     * empty strings.</p>
    4455     *
    4456     * <pre>
    4457     * StringUtils.join(null, *)               = null
    4458     * StringUtils.join([], *)                 = ""
    4459     * StringUtils.join([null], *)             = ""
    4460     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4461     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4462     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4463     * </pre>
    4464     *
    4465     * @param list  the {@link List} of values to join together, may be null
    4466     * @param separator  the separator character to use
    4467     * @param startIndex the first index to start joining from.  It is
    4468     * an error to pass in a start index past the end of the list
    4469     * @param endIndex the index to stop joining from (exclusive). It is
    4470     * an error to pass in an end index past the end of the list
    4471     * @return the joined String, {@code null} if null list input
    4472     * @since 3.8
    4473     */
    4474    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
    4475        if (list == null) {
    4476            return null;
    4477        }
    4478        final int noOfItems = endIndex - startIndex;
    4479        if (noOfItems <= 0) {
    4480            return EMPTY;
    4481        }
    4482        final List<?> subList = list.subList(startIndex, endIndex);
    4483        return join(subList.iterator(), separator);
    4484    }
    4485
    4486    /**
    4487     * Joins the elements of the provided {@link List} into a single String
    4488     * containing the provided list of elements.
    4489     *
    4490     * <p>No delimiter is added before or after the list.
    4491     * Null objects or empty strings within the array are represented by
    4492     * empty strings.</p>
    4493     *
    4494     * <pre>
    4495     * StringUtils.join(null, *)               = null
    4496     * StringUtils.join([], *)                 = ""
    4497     * StringUtils.join([null], *)             = ""
    4498     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4499     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4500     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4501     * </pre>
    4502     *
    4503     * @param list  the {@link List} of values to join together, may be null
    4504     * @param separator  the separator character to use
    4505     * @param startIndex the first index to start joining from.  It is
    4506     * an error to pass in a start index past the end of the list
    4507     * @param endIndex the index to stop joining from (exclusive). It is
    4508     * an error to pass in an end index past the end of the list
    4509     * @return the joined String, {@code null} if null list input
    4510     * @since 3.8
    4511     */
    4512    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
    4513        if (list == null) {
    4514            return null;
    4515        }
    4516        final int noOfItems = endIndex - startIndex;
    4517        if (noOfItems <= 0) {
    4518            return EMPTY;
    4519        }
    4520        final List<?> subList = list.subList(startIndex, endIndex);
    4521        return join(subList.iterator(), separator);
    4522    }
    4523
    4524    /**
    4525     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4526     *
    4527     * <p>
    4528     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4529     * by empty strings.
    4530     * </p>
    4531     *
    4532     * <pre>
    4533     * StringUtils.join(null, *)               = null
    4534     * StringUtils.join([], *)                 = ""
    4535     * StringUtils.join([null], *)             = ""
    4536     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4537     * StringUtils.join([1, 2, 3], null) = "123"
    4538     * </pre>
    4539     *
    4540     * @param array
    4541     *            the array of values to join together, may be null
    4542     * @param separator
    4543     *            the separator character to use
    4544     * @return the joined String, {@code null} if null array input
    4545     * @since 3.2
    4546     */
    4547    public static String join(final long[] array, final char separator) {
    4548        if (array == null) {
    4549            return null;
    4550        }
    4551        return join(array, separator, 0, array.length);
    4552    }
    4553
    4554    /**
    4555     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4556     *
    4557     * <p>
    4558     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4559     * by empty strings.
    4560     * </p>
    4561     *
    4562     * <pre>
    4563     * StringUtils.join(null, *)               = null
    4564     * StringUtils.join([], *)                 = ""
    4565     * StringUtils.join([null], *)             = ""
    4566     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4567     * StringUtils.join([1, 2, 3], null) = "123"
    4568     * </pre>
    4569     *
    4570     * @param array
    4571     *            the array of values to join together, may be null
    4572     * @param delimiter
    4573     *            the separator character to use
    4574     * @param startIndex
    4575     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4576     *            array
    4577     * @param endIndex
    4578     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4579     *            the array
    4580     * @return the joined String, {@code null} if null array input
    4581     * @since 3.2
    4582     */
    4583    public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
    4584        if (array == null) {
    4585            return null;
    4586        }
    4587        if (endIndex - startIndex <= 0) {
    4588            return EMPTY;
    4589        }
    4590        final StringBuilder stringBuilder = new StringBuilder();
    4591        for (int i = startIndex; i < endIndex; i++) {
    4592            stringBuilder
    4593                    .append(array[i])
    4594                    .append(delimiter);
    4595        }
    4596        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4597    }
    4598
    4599    /**
    4600     * Joins the elements of the provided array into a single String
    4601     * containing the provided list of elements.
    4602     *
    4603     * <p>No delimiter is added before or after the list.
    4604     * Null objects or empty strings within the array are represented by
    4605     * empty strings.</p>
    4606     *
    4607     * <pre>
    4608     * StringUtils.join(null, *)               = null
    4609     * StringUtils.join([], *)                 = ""
    4610     * StringUtils.join([null], *)             = ""
    4611     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4612     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4613     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4614     * </pre>
    4615     *
    4616     * @param array  the array of values to join together, may be null
    4617     * @param delimiter  the separator character to use
    4618     * @return the joined String, {@code null} if null array input
    4619     * @since 2.0
    4620     */
    4621    public static String join(final Object[] array, final char delimiter) {
    4622        if (array == null) {
    4623            return null;
    4624        }
    4625        return join(array, delimiter, 0, array.length);
    4626    }
    4627
    4628    /**
    4629     * Joins the elements of the provided array into a single String
    4630     * containing the provided list of elements.
    4631     *
    4632     * <p>No delimiter is added before or after the list.
    4633     * Null objects or empty strings within the array are represented by
    4634     * empty strings.</p>
    4635     *
    4636     * <pre>
    4637     * StringUtils.join(null, *)               = null
    4638     * StringUtils.join([], *)                 = ""
    4639     * StringUtils.join([null], *)             = ""
    4640     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4641     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4642     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4643     * </pre>
    4644     *
    4645     * @param array  the array of values to join together, may be null
    4646     * @param delimiter  the separator character to use
    4647     * @param startIndex the first index to start joining from.  It is
    4648     * an error to pass in a start index past the end of the array
    4649     * @param endIndex the index to stop joining from (exclusive). It is
    4650     * an error to pass in an end index past the end of the array
    4651     * @return the joined String, {@code null} if null array input
    4652     * @since 2.0
    4653     */
    4654    public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
    4655        return join(array, String.valueOf(delimiter), startIndex, endIndex);
    4656    }
    4657
    4658    /**
    4659     * Joins the elements of the provided array into a single String
    4660     * containing the provided list of elements.
    4661     *
    4662     * <p>No delimiter is added before or after the list.
    4663     * A {@code null} separator is the same as an empty String ("").
    4664     * Null objects or empty strings within the array are represented by
    4665     * empty strings.</p>
    4666     *
    4667     * <pre>
    4668     * StringUtils.join(null, *)                = null
    4669     * StringUtils.join([], *)                  = ""
    4670     * StringUtils.join([null], *)              = ""
    4671     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    4672     * StringUtils.join(["a", "b", "c"], null)  = "abc"
    4673     * StringUtils.join(["a", "b", "c"], "")    = "abc"
    4674     * StringUtils.join([null, "", "a"], ',')   = ",,a"
    4675     * </pre>
    4676     *
    4677     * @param array  the array of values to join together, may be null
    4678     * @param delimiter  the separator character to use, null treated as ""
    4679     * @return the joined String, {@code null} if null array input
    4680     */
    4681    public static String join(final Object[] array, final String delimiter) {
    4682        return array != null ? join(array, toStringOrEmpty(delimiter), 0, array.length) : null;
    4683    }
    4684
    4685    /**
    4686     * Joins the elements of the provided array into a single String
    4687     * containing the provided list of elements.
    4688     *
    4689     * <p>No delimiter is added before or after the list.
    4690     * A {@code null} separator is the same as an empty String ("").
    4691     * Null objects or empty strings within the array are represented by
    4692     * empty strings.</p>
    4693     *
    4694     * <pre>
    4695     * StringUtils.join(null, *, *, *)                = null
    4696     * StringUtils.join([], *, *, *)                  = ""
    4697     * StringUtils.join([null], *, *, *)              = ""
    4698     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
    4699     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
    4700     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
    4701     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
    4702     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
    4703     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
    4704     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
    4705     * </pre>
    4706     *
    4707     * @param array  the array of values to join together, may be null
    4708     * @param delimiter  the separator character to use, null treated as ""
    4709     * @param startIndex the first index to start joining from.
    4710     * @param endIndex the index to stop joining from (exclusive).
    4711     * @return the joined String, {@code null} if null array input; or the empty string
    4712     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
    4713     * {@code endIndex - startIndex}
    4714     * @throws ArrayIndexOutOfBoundsException ife<br>
    4715     * {@code startIndex < 0} or <br>
    4716     * {@code startIndex >= array.length()} or <br>
    4717     * {@code endIndex < 0} or <br>
    4718     * {@code endIndex > array.length()}
    4719     */
    4720    public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
    4721        return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
    4722            .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, StringUtils::toStringOrEmpty)) : null;
    4723    }
    4724
    4725    /**
    4726     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4727     *
    4728     * <p>
    4729     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4730     * by empty strings.
    4731     * </p>
    4732     *
    4733     * <pre>
    4734     * StringUtils.join(null, *)               = null
    4735     * StringUtils.join([], *)                 = ""
    4736     * StringUtils.join([null], *)             = ""
    4737     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4738     * StringUtils.join([1, 2, 3], null) = "123"
    4739     * </pre>
    4740     *
    4741     * @param array
    4742     *            the array of values to join together, may be null
    4743     * @param delimiter
    4744     *            the separator character to use
    4745     * @return the joined String, {@code null} if null array input
    4746     * @since 3.2
    4747     */
    4748    public static String join(final short[] array, final char delimiter) {
    4749        if (array == null) {
    4750            return null;
    4751        }
    4752        return join(array, delimiter, 0, array.length);
    4753    }
    4754
    4755    /**
    4756     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4757     *
    4758     * <p>
    4759     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4760     * by empty strings.
    4761     * </p>
    4762     *
    4763     * <pre>
    4764     * StringUtils.join(null, *)               = null
    4765     * StringUtils.join([], *)                 = ""
    4766     * StringUtils.join([null], *)             = ""
    4767     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4768     * StringUtils.join([1, 2, 3], null) = "123"
    4769     * </pre>
    4770     *
    4771     * @param array
    4772     *            the array of values to join together, may be null
    4773     * @param delimiter
    4774     *            the separator character to use
    4775     * @param startIndex
    4776     *            the first index to start joining from. It is an error to pass in a start index past the end of the
    4777     *            array
    4778     * @param endIndex
    4779     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4780     *            the array
    4781     * @return the joined String, {@code null} if null array input
    4782     * @since 3.2
    4783     */
    4784    public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
    4785        if (array == null) {
    4786            return null;
    4787        }
    4788        if (endIndex - startIndex <= 0) {
    4789            return EMPTY;
    4790        }
    4791        final StringBuilder stringBuilder = new StringBuilder();
    4792        for (int i = startIndex; i < endIndex; i++) {
    4793            stringBuilder
    4794                    .append(array[i])
    4795                    .append(delimiter);
    4796        }
    4797        return stringBuilder.substring(0, stringBuilder.length() - 1);
    4798    }
    4799
    4800    /**
    4801     * Joins the elements of the provided array into a single String
    4802     * containing the provided list of elements.
    4803     *
    4804     * <p>No separator is added to the joined String.
    4805     * Null objects or empty strings within the array are represented by
    4806     * empty strings.</p>
    4807     *
    4808     * <pre>
    4809     * StringUtils.join(null)            = null
    4810     * StringUtils.join([])              = ""
    4811     * StringUtils.join([null])          = ""
    4812     * StringUtils.join(["a", "b", "c"]) = "abc"
    4813     * StringUtils.join([null, "", "a"]) = "a"
    4814     * </pre>
    4815     *
    4816     * @param <T> the specific type of values to join together
    4817     * @param elements  the values to join together, may be null
    4818     * @return the joined String, {@code null} if null array input
    4819     * @since 2.0
    4820     * @since 3.0 Changed signature to use varargs
    4821     */
    4822    @SafeVarargs
    4823    public static <T> String join(final T... elements) {
    4824        return join(elements, null);
    4825    }
    4826
    4827    /**
    4828     * Joins the elements of the provided varargs into a
    4829     * single String containing the provided elements.
    4830     *
    4831     * <p>No delimiter is added before or after the list.
    4832     * {@code null} elements and separator are treated as empty Strings ("").</p>
    4833     *
    4834     * <pre>
    4835     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
    4836     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
    4837     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
    4838     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
    4839     * </pre>
    4840     *
    4841     * @param delimiter the separator character to use, null treated as ""
    4842     * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
    4843     * @return the joined String.
    4844     * @throws IllegalArgumentException if a null varargs is provided
    4845     * @since 3.5
    4846     */
    4847    public static String joinWith(final String delimiter, final Object... array) {
    4848        if (array == null) {
    4849            throw new IllegalArgumentException("Object varargs must not be null");
    4850        }
    4851        return join(array, delimiter);
    4852    }
    4853
    4854    /**
    4855     * Finds the last index within a CharSequence, handling {@code null}.
    4856     * This method uses {@link String#lastIndexOf(String)} if possible.
    4857     *
    4858     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    4859     *
    4860     * <pre>
    4861     * StringUtils.lastIndexOf(null, *)          = -1
    4862     * StringUtils.lastIndexOf(*, null)          = -1
    4863     * StringUtils.lastIndexOf("", "")           = 0
    4864     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    4865     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    4866     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    4867     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    4868     * </pre>
    4869     *
    4870     * @param seq  the CharSequence to check, may be null
    4871     * @param searchSeq  the CharSequence to find, may be null
    4872     * @return the last index of the search String,
    4873     *  -1 if no match or {@code null} string input
    4874     * @since 2.0
    4875     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
    4876     */
    4877    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
    4878        if (seq == null) {
    4879            return INDEX_NOT_FOUND;
    4880        }
    4881        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
    4882    }
    4883
    4884    /**
    4885     * Finds the last index within a CharSequence, handling {@code null}.
    4886     * This method uses {@link String#lastIndexOf(String, int)} if possible.
    4887     *
    4888     * <p>A {@code null} CharSequence will return {@code -1}.
    4889     * A negative start position returns {@code -1}.
    4890     * An empty ("") search CharSequence always matches unless the start position is negative.
    4891     * A start position greater than the string length searches the whole string.
    4892     * The search starts at the startPos and works backwards; matches starting after the start
    4893     * position are ignored.
    4894     * </p>
    4895     *
    4896     * <pre>
    4897     * StringUtils.lastIndexOf(null, *, *)          = -1
    4898     * StringUtils.lastIndexOf(*, null, *)          = -1
    4899     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    4900     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    4901     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    4902     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    4903     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    4904     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    4905     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    4906     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
    4907     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
    4908     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
    4909     * </pre>
    4910     *
    4911     * @param seq  the CharSequence to check, may be null
    4912     * @param searchSeq  the CharSequence to find, may be null
    4913     * @param startPos  the start position, negative treated as zero
    4914     * @return the last index of the search CharSequence (always &le; startPos),
    4915     *  -1 if no match or {@code null} string input
    4916     * @since 2.0
    4917     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
    4918     */
    4919    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    4920        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
    4921    }
    4922
    4923    /**
    4924     * Returns the index within {@code seq} of the last occurrence of
    4925     * the specified character. For values of {@code searchChar} in the
    4926     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
    4927     * units) returned is the largest value <i>k</i> such that:
    4928     * <blockquote><pre>
    4929     * this.charAt(<i>k</i>) == searchChar
    4930     * </pre></blockquote>
    4931     * is true. For other values of {@code searchChar}, it is the
    4932     * largest value <i>k</i> such that:
    4933     * <blockquote><pre>
    4934     * this.codePointAt(<i>k</i>) == searchChar
    4935     * </pre></blockquote>
    4936     * is true.  In either case, if no such character occurs in this
    4937     * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4938     * {@link CharSequence} will return {@code -1}. The
    4939     * {@code seq} {@link CharSequence} object is searched backwards
    4940     * starting at the last character.
    4941     *
    4942     * <pre>
    4943     * StringUtils.lastIndexOf(null, *)         = -1
    4944     * StringUtils.lastIndexOf("", *)           = -1
    4945     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    4946     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    4947     * </pre>
    4948     *
    4949     * @param seq  the {@link CharSequence} to check, may be null
    4950     * @param searchChar  the character to find
    4951     * @return the last index of the search character,
    4952     *  -1 if no match or {@code null} string input
    4953     * @since 2.0
    4954     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
    4955     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
    4956     */
    4957    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
    4958        if (isEmpty(seq)) {
    4959            return INDEX_NOT_FOUND;
    4960        }
    4961        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
    4962    }
    4963
    4964    /**
    4965     * Returns the index within {@code seq} of the last occurrence of
    4966     * the specified character, searching backward starting at the
    4967     * specified index. For values of {@code searchChar} in the range
    4968     * from 0 to 0xFFFF (inclusive), the index returned is the largest
    4969     * value <i>k</i> such that:
    4970     * <blockquote><pre>
    4971     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    4972     * </pre></blockquote>
    4973     * is true. For other values of {@code searchChar}, it is the
    4974     * largest value <i>k</i> such that:
    4975     * <blockquote><pre>
    4976     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    4977     * </pre></blockquote>
    4978     * is true. In either case, if no such character occurs in {@code seq}
    4979     * at or before position {@code startPos}, then
    4980     * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
    4981     * {@link CharSequence} will return {@code -1}. A start position greater
    4982     * than the string length searches the whole string.
    4983     * The search starts at the {@code startPos} and works backwards;
    4984     * matches starting after the start position are ignored.
    4985     *
    4986     * <p>All indices are specified in {@code char} values
    4987     * (Unicode code units).
    4988     *
    4989     * <pre>
    4990     * StringUtils.lastIndexOf(null, *, *)          = -1
    4991     * StringUtils.lastIndexOf("", *,  *)           = -1
    4992     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    4993     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    4994     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    4995     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    4996     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    4997     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    4998     * </pre>
    4999     *
    5000     * @param seq  the CharSequence to check, may be null
    5001     * @param searchChar  the character to find
    5002     * @param startPos  the start position
    5003     * @return the last index of the search character (always &le; startPos),
    5004     *  -1 if no match or {@code null} string input
    5005     * @since 2.0
    5006     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
    5007     */
    5008    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
    5009        if (isEmpty(seq)) {
    5010            return INDEX_NOT_FOUND;
    5011        }
    5012        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
    5013    }
    5014
    5015    /**
    5016     * Find the latest index of any substring in a set of potential substrings.
    5017     *
    5018     * <p>A {@code null} CharSequence will return {@code -1}.
    5019     * A {@code null} search array will return {@code -1}.
    5020     * A {@code null} or zero length search array entry will be ignored,
    5021     * but a search array containing "" will return the length of {@code str}
    5022     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
    5023     *
    5024     * <pre>
    5025     * StringUtils.lastIndexOfAny(null, *)                    = -1
    5026     * StringUtils.lastIndexOfAny(*, null)                    = -1
    5027     * StringUtils.lastIndexOfAny(*, [])                      = -1
    5028     * StringUtils.lastIndexOfAny(*, [null])                  = -1
    5029     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
    5030     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
    5031     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    5032     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
    5033     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
    5034     * </pre>
    5035     *
    5036     * @param str  the CharSequence to check, may be null
    5037     * @param searchStrs  the CharSequences to search for, may be null
    5038     * @return the last index of any of the CharSequences, -1 if no match
    5039     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
    5040     */
    5041    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    5042        if (str == null || searchStrs == null) {
    5043            return INDEX_NOT_FOUND;
    5044        }
    5045        int ret = INDEX_NOT_FOUND;
    5046        int tmp;
    5047        for (final CharSequence search : searchStrs) {
    5048            if (search == null) {
    5049                continue;
    5050            }
    5051            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
    5052            if (tmp > ret) {
    5053                ret = tmp;
    5054            }
    5055        }
    5056        return ret;
    5057    }
    5058
    5059    /**
    5060     * Case in-sensitive find of the last index within a CharSequence.
    5061     *
    5062     * <p>A {@code null} CharSequence will return {@code -1}.
    5063     * A negative start position returns {@code -1}.
    5064     * An empty ("") search CharSequence always matches unless the start position is negative.
    5065     * A start position greater than the string length searches the whole string.</p>
    5066     *
    5067     * <pre>
    5068     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    5069     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    5070     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    5071     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    5072     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    5073     * </pre>
    5074     *
    5075     * @param str  the CharSequence to check, may be null
    5076     * @param searchStr  the CharSequence to find, may be null
    5077     * @return the first index of the search CharSequence,
    5078     *  -1 if no match or {@code null} string input
    5079     * @since 2.5
    5080     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
    5081     */
    5082    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    5083        if (str == null || searchStr == null) {
    5084            return INDEX_NOT_FOUND;
    5085        }
    5086        return lastIndexOfIgnoreCase(str, searchStr, str.length());
    5087    }
    5088
    5089    /**
    5090     * Case in-sensitive find of the last index within a CharSequence
    5091     * from the specified position.
    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.
    5097     * The search starts at the startPos and works backwards; matches starting after the start
    5098     * position are ignored.
    5099     * </p>
    5100     *
    5101     * <pre>
    5102     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    5103     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    5104     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    5105     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    5106     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    5107     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    5108     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    5109     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    5110     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    5111     * </pre>
    5112     *
    5113     * @param str  the CharSequence to check, may be null
    5114     * @param searchStr  the CharSequence to find, may be null
    5115     * @param startPos  the start position
    5116     * @return the last index of the search CharSequence (always &le; startPos),
    5117     *  -1 if no match or {@code null} input
    5118     * @since 2.5
    5119     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
    5120     */
    5121    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    5122        if (str == null || searchStr == null) {
    5123            return INDEX_NOT_FOUND;
    5124        }
    5125        final int searchStrLength = searchStr.length();
    5126        final int strLength = str.length();
    5127        if (startPos > strLength - searchStrLength) {
    5128            startPos = strLength - searchStrLength;
    5129        }
    5130        if (startPos < 0) {
    5131            return INDEX_NOT_FOUND;
    5132        }
    5133        if (searchStrLength == 0) {
    5134            return startPos;
    5135        }
    5136
    5137        for (int i = startPos; i >= 0; i--) {
    5138            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) {
    5139                return i;
    5140            }
    5141        }
    5142        return INDEX_NOT_FOUND;
    5143    }
    5144
    5145    /**
    5146     * Finds the n-th last index within a String, handling {@code null}.
    5147     * This method uses {@link String#lastIndexOf(String)}.
    5148     *
    5149     * <p>A {@code null} String will return {@code -1}.</p>
    5150     *
    5151     * <pre>
    5152     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    5153     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    5154     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    5155     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    5156     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    5157     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    5158     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    5159     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    5160     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    5161     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    5162     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    5163     * </pre>
    5164     *
    5165     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
    5166     *
    5167     * <pre>
    5168     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    5169     * </pre>
    5170     *
    5171     * @param str  the CharSequence to check, may be null
    5172     * @param searchStr  the CharSequence to find, may be null
    5173     * @param ordinal  the n-th last {@code searchStr} to find
    5174     * @return the n-th last index of the search CharSequence,
    5175     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5176     * @since 2.5
    5177     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
    5178     */
    5179    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5180        return ordinalIndexOf(str, searchStr, ordinal, true);
    5181    }
    5182
    5183    /**
    5184     * Gets the leftmost {@code len} characters of a String.
    5185     *
    5186     * <p>If {@code len} characters are not available, or the
    5187     * String is {@code null}, the String will be returned without
    5188     * an exception. An empty String is returned if len is negative.</p>
    5189     *
    5190     * <pre>
    5191     * StringUtils.left(null, *)    = null
    5192     * StringUtils.left(*, -ve)     = ""
    5193     * StringUtils.left("", *)      = ""
    5194     * StringUtils.left("abc", 0)   = ""
    5195     * StringUtils.left("abc", 2)   = "ab"
    5196     * StringUtils.left("abc", 4)   = "abc"
    5197     * </pre>
    5198     *
    5199     * @param str  the String to get the leftmost characters from, may be null
    5200     * @param len  the length of the required String
    5201     * @return the leftmost characters, {@code null} if null String input
    5202     */
    5203    public static String left(final String str, final int len) {
    5204        if (str == null) {
    5205            return null;
    5206        }
    5207        if (len < 0) {
    5208            return EMPTY;
    5209        }
    5210        if (str.length() <= len) {
    5211            return str;
    5212        }
    5213        return str.substring(0, len);
    5214    }
    5215
    5216    /**
    5217     * Left pad a String with spaces (' ').
    5218     *
    5219     * <p>The String is padded to the size of {@code size}.</p>
    5220     *
    5221     * <pre>
    5222     * StringUtils.leftPad(null, *)   = null
    5223     * StringUtils.leftPad("", 3)     = "   "
    5224     * StringUtils.leftPad("bat", 3)  = "bat"
    5225     * StringUtils.leftPad("bat", 5)  = "  bat"
    5226     * StringUtils.leftPad("bat", 1)  = "bat"
    5227     * StringUtils.leftPad("bat", -1) = "bat"
    5228     * </pre>
    5229     *
    5230     * @param str  the String to pad out, may be null
    5231     * @param size  the size to pad to
    5232     * @return left padded String or original String if no padding is necessary,
    5233     *  {@code null} if null String input
    5234     */
    5235    public static String leftPad(final String str, final int size) {
    5236        return leftPad(str, size, ' ');
    5237    }
    5238
    5239    /**
    5240     * Left pad a String with a specified character.
    5241     *
    5242     * <p>Pad to a size of {@code size}.</p>
    5243     *
    5244     * <pre>
    5245     * StringUtils.leftPad(null, *, *)     = null
    5246     * StringUtils.leftPad("", 3, 'z')     = "zzz"
    5247     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    5248     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    5249     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    5250     * StringUtils.leftPad("bat", -1, 'z') = "bat"
    5251     * </pre>
    5252     *
    5253     * @param str  the String to pad out, may be null
    5254     * @param size  the size to pad to
    5255     * @param padChar  the character to pad with
    5256     * @return left padded String or original String if no padding is necessary,
    5257     *  {@code null} if null String input
    5258     * @since 2.0
    5259     */
    5260    public static String leftPad(final String str, final int size, final char padChar) {
    5261        if (str == null) {
    5262            return null;
    5263        }
    5264        final int pads = size - str.length();
    5265        if (pads <= 0) {
    5266            return str; // returns original String when possible
    5267        }
    5268        if (pads > PAD_LIMIT) {
    5269            return leftPad(str, size, String.valueOf(padChar));
    5270        }
    5271        return repeat(padChar, pads).concat(str);
    5272    }
    5273
    5274    /**
    5275     * Left pad a String with a specified String.
    5276     *
    5277     * <p>Pad to a size of {@code size}.</p>
    5278     *
    5279     * <pre>
    5280     * StringUtils.leftPad(null, *, *)      = null
    5281     * StringUtils.leftPad("", 3, "z")      = "zzz"
    5282     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    5283     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    5284     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    5285     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    5286     * StringUtils.leftPad("bat", -1, "yz") = "bat"
    5287     * StringUtils.leftPad("bat", 5, null)  = "  bat"
    5288     * StringUtils.leftPad("bat", 5, "")    = "  bat"
    5289     * </pre>
    5290     *
    5291     * @param str  the String to pad out, may be null
    5292     * @param size  the size to pad to
    5293     * @param padStr  the String to pad with, null or empty treated as single space
    5294     * @return left padded String or original String if no padding is necessary,
    5295     *  {@code null} if null String input
    5296     */
    5297    public static String leftPad(final String str, final int size, String padStr) {
    5298        if (str == null) {
    5299            return null;
    5300        }
    5301        if (isEmpty(padStr)) {
    5302            padStr = SPACE;
    5303        }
    5304        final int padLen = padStr.length();
    5305        final int strLen = str.length();
    5306        final int pads = size - strLen;
    5307        if (pads <= 0) {
    5308            return str; // returns original String when possible
    5309        }
    5310        if (padLen == 1 && pads <= PAD_LIMIT) {
    5311            return leftPad(str, size, padStr.charAt(0));
    5312        }
    5313
    5314        if (pads == padLen) {
    5315            return padStr.concat(str);
    5316        }
    5317        if (pads < padLen) {
    5318            return padStr.substring(0, pads).concat(str);
    5319        }
    5320        final char[] padding = new char[pads];
    5321        final char[] padChars = padStr.toCharArray();
    5322        for (int i = 0; i < pads; i++) {
    5323            padding[i] = padChars[i % padLen];
    5324        }
    5325        return new String(padding).concat(str);
    5326    }
    5327
    5328    /**
    5329     * Gets a CharSequence length or {@code 0} if the CharSequence is
    5330     * {@code null}.
    5331     *
    5332     * @param cs
    5333     *            a CharSequence or {@code null}
    5334     * @return CharSequence length or {@code 0} if the CharSequence is
    5335     *         {@code null}.
    5336     * @since 2.4
    5337     * @since 3.0 Changed signature from length(String) to length(CharSequence)
    5338     */
    5339    public static int length(final CharSequence cs) {
    5340        return cs == null ? 0 : cs.length();
    5341    }
    5342
    5343    /**
    5344     * Converts a String to lower case as per {@link String#toLowerCase()}.
    5345     *
    5346     * <p>A {@code null} input String returns {@code null}.</p>
    5347     *
    5348     * <pre>
    5349     * StringUtils.lowerCase(null)  = null
    5350     * StringUtils.lowerCase("")    = ""
    5351     * StringUtils.lowerCase("aBc") = "abc"
    5352     * </pre>
    5353     *
    5354     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
    5355     * the result of this method is affected by the current locale.
    5356     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    5357     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    5358     *
    5359     * @param str  the String to lower case, may be null
    5360     * @return the lower cased String, {@code null} if null String input
    5361     */
    5362    public static String lowerCase(final String str) {
    5363        if (str == null) {
    5364            return null;
    5365        }
    5366        return str.toLowerCase();
    5367    }
    5368
    5369    /**
    5370     * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
    5371     *
    5372     * <p>A {@code null} input String returns {@code null}.</p>
    5373     *
    5374     * <pre>
    5375     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    5376     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    5377     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    5378     * </pre>
    5379     *
    5380     * @param str  the String to lower case, may be null
    5381     * @param locale  the locale that defines the case transformation rules, must not be null
    5382     * @return the lower cased String, {@code null} if null String input
    5383     * @since 2.5
    5384     */
    5385    public static String lowerCase(final String str, final Locale locale) {
    5386        if (str == null) {
    5387            return null;
    5388        }
    5389        return str.toLowerCase(LocaleUtils.toLocale(locale));
    5390    }
    5391
    5392    private static int[] matches(final CharSequence first, final CharSequence second) {
    5393        final CharSequence max;
    5394        final CharSequence min;
    5395        if (first.length() > second.length()) {
    5396            max = first;
    5397            min = second;
    5398        } else {
    5399            max = second;
    5400            min = first;
    5401        }
    5402        final int range = Math.max(max.length() / 2 - 1, 0);
    5403        final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
    5404        final boolean[] matchFlags = new boolean[max.length()];
    5405        int matches = 0;
    5406        for (int mi = 0; mi < min.length(); mi++) {
    5407            final char c1 = min.charAt(mi);
    5408            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
    5409                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
    5410                    matchIndexes[mi] = xi;
    5411                    matchFlags[xi] = true;
    5412                    matches++;
    5413                    break;
    5414                }
    5415            }
    5416        }
    5417        final char[] ms1 = new char[matches];
    5418        final char[] ms2 = new char[matches];
    5419        for (int i = 0, si = 0; i < min.length(); i++) {
    5420            if (matchIndexes[i] != -1) {
    5421                ms1[si] = min.charAt(i);
    5422                si++;
    5423            }
    5424        }
    5425        for (int i = 0, si = 0; i < max.length(); i++) {
    5426            if (matchFlags[i]) {
    5427                ms2[si] = max.charAt(i);
    5428                si++;
    5429            }
    5430        }
    5431        int transpositions = 0;
    5432        for (int mi = 0; mi < ms1.length; mi++) {
    5433            if (ms1[mi] != ms2[mi]) {
    5434                transpositions++;
    5435            }
    5436        }
    5437        int prefix = 0;
    5438        for (int mi = 0; mi < min.length(); mi++) {
    5439            if (first.charAt(mi) != second.charAt(mi)) {
    5440                break;
    5441            }
    5442            prefix++;
    5443        }
    5444        return new int[] { matches, transpositions / 2, prefix, max.length() };
    5445    }
    5446
    5447    /**
    5448     * Gets {@code len} characters from the middle of a String.
    5449     *
    5450     * <p>If {@code len} characters are not available, the remainder
    5451     * of the String will be returned without an exception. If the
    5452     * String is {@code null}, {@code null} will be returned.
    5453     * An empty String is returned if len is negative or exceeds the
    5454     * length of {@code str}.</p>
    5455     *
    5456     * <pre>
    5457     * StringUtils.mid(null, *, *)    = null
    5458     * StringUtils.mid(*, *, -ve)     = ""
    5459     * StringUtils.mid("", 0, *)      = ""
    5460     * StringUtils.mid("abc", 0, 2)   = "ab"
    5461     * StringUtils.mid("abc", 0, 4)   = "abc"
    5462     * StringUtils.mid("abc", 2, 4)   = "c"
    5463     * StringUtils.mid("abc", 4, 2)   = ""
    5464     * StringUtils.mid("abc", -2, 2)  = "ab"
    5465     * </pre>
    5466     *
    5467     * @param str  the String to get the characters from, may be null
    5468     * @param pos  the position to start from, negative treated as zero
    5469     * @param len  the length of the required String
    5470     * @return the middle characters, {@code null} if null String input
    5471     */
    5472    public static String mid(final String str, int pos, final int len) {
    5473        if (str == null) {
    5474            return null;
    5475        }
    5476        if (len < 0 || pos > str.length()) {
    5477            return EMPTY;
    5478        }
    5479        if (pos < 0) {
    5480            pos = 0;
    5481        }
    5482        if (str.length() <= pos + len) {
    5483            return str.substring(pos);
    5484        }
    5485        return str.substring(pos, pos + len);
    5486    }
    5487
    5488    /**
    5489     * Similar to <a
    5490     * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
    5491     * -space</a>
    5492     *
    5493     * <p>
    5494     * The function returns the argument string with whitespace normalized by using
    5495     * {@code {@link #trim(String)}} to remove leading and trailing whitespace
    5496     * and then replacing sequences of whitespace characters by a single space.
    5497     * </p>
    5498     * In XML Whitespace characters are the same as those allowed by the <a
    5499     * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
    5500     * <p>
    5501     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
    5502     *
    5503     * <p>For reference:</p>
    5504     * <ul>
    5505     * <li>\x0B = vertical tab</li>
    5506     * <li>\f = #xC = form feed</li>
    5507     * <li>#x20 = space</li>
    5508     * <li>#x9 = \t</li>
    5509     * <li>#xA = \n</li>
    5510     * <li>#xD = \r</li>
    5511     * </ul>
    5512     *
    5513     * <p>
    5514     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
    5515     * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
    5516     * ends of this String.
    5517     * </p>
    5518     *
    5519     * @see Pattern
    5520     * @see #trim(String)
    5521     * @see <a
    5522     *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
    5523     * @param str the source String to normalize whitespaces from, may be null
    5524     * @return the modified string with whitespace normalized, {@code null} if null String input
    5525     *
    5526     * @since 3.0
    5527     */
    5528    public static String normalizeSpace(final String str) {
    5529        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
    5530        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
    5531        if (isEmpty(str)) {
    5532            return str;
    5533        }
    5534        final int size = str.length();
    5535        final char[] newChars = new char[size];
    5536        int count = 0;
    5537        int whitespacesCount = 0;
    5538        boolean startWhitespaces = true;
    5539        for (int i = 0; i < size; i++) {
    5540            final char actualChar = str.charAt(i);
    5541            final boolean isWhitespace = Character.isWhitespace(actualChar);
    5542            if (isWhitespace) {
    5543                if (whitespacesCount == 0 && !startWhitespaces) {
    5544                    newChars[count++] = SPACE.charAt(0);
    5545                }
    5546                whitespacesCount++;
    5547            } else {
    5548                startWhitespaces = false;
    5549                newChars[count++] = actualChar == 160 ? 32 : actualChar;
    5550                whitespacesCount = 0;
    5551            }
    5552        }
    5553        if (startWhitespaces) {
    5554            return EMPTY;
    5555        }
    5556        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
    5557    }
    5558
    5559    /**
    5560     * Finds the n-th index within a CharSequence, handling {@code null}.
    5561     * This method uses {@link String#indexOf(String)} if possible.
    5562     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
    5563     * incrementing the starting index by one after each successful match
    5564     * (unless {@code searchStr} is an empty string in which case the position
    5565     * is never incremented and {@code 0} is returned immediately).
    5566     * This means that matches may overlap.</p>
    5567     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5568     *
    5569     * <pre>
    5570     * StringUtils.ordinalIndexOf(null, *, *)          = -1
    5571     * StringUtils.ordinalIndexOf(*, null, *)          = -1
    5572     * StringUtils.ordinalIndexOf("", "", *)           = 0
    5573     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    5574     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    5575     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    5576     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    5577     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    5578     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    5579     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    5580     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    5581     * </pre>
    5582     *
    5583     * <p>Matches may overlap:</p>
    5584     * <pre>
    5585     * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
    5586     * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
    5587     * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
    5588     *
    5589     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
    5590     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
    5591     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
    5592     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
    5593     * </pre>
    5594     *
    5595     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
    5596     *
    5597     * <pre>
    5598     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    5599     * </pre>
    5600     *
    5601     * @param str  the CharSequence to check, may be null
    5602     * @param searchStr  the CharSequence to find, may be null
    5603     * @param ordinal  the n-th {@code searchStr} to find
    5604     * @return the n-th index of the search CharSequence,
    5605     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5606     * @since 2.1
    5607     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
    5608     */
    5609    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    5610        return ordinalIndexOf(str, searchStr, ordinal, false);
    5611    }
    5612
    5613    /**
    5614     * Finds the n-th index within a String, handling {@code null}.
    5615     * This method uses {@link String#indexOf(String)} if possible.
    5616     * <p>Note that matches may overlap<p>
    5617     *
    5618     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    5619     *
    5620     * @param str  the CharSequence to check, may be null
    5621     * @param searchStr  the CharSequence to find, may be null
    5622     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
    5623     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
    5624     * @return the n-th index of the search CharSequence,
    5625     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    5626     */
    5627    // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
    5628    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
    5629        if (str == null || searchStr == null || ordinal <= 0) {
    5630            return INDEX_NOT_FOUND;
    5631        }
    5632        if (searchStr.length() == 0) {
    5633            return lastIndex ? str.length() : 0;
    5634        }
    5635        int found = 0;
    5636        // set the initial index beyond the end of the string
    5637        // this is to allow for the initial index decrement/increment
    5638        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    5639        do {
    5640            if (lastIndex) {
    5641                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
    5642            } else {
    5643                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
    5644            }
    5645            if (index < 0) {
    5646                return index;
    5647            }
    5648            found++;
    5649        } while (found < ordinal);
    5650        return index;
    5651    }
    5652
    5653    /**
    5654     * Overlays part of a String with another String.
    5655     *
    5656     * <p>A {@code null} string input returns {@code null}.
    5657     * A negative index is treated as zero.
    5658     * An index greater than the string length is treated as the string length.
    5659     * The start index is always the smaller of the two indices.</p>
    5660     *
    5661     * <pre>
    5662     * StringUtils.overlay(null, *, *, *)            = null
    5663     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    5664     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    5665     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    5666     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    5667     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    5668     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    5669     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    5670     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    5671     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    5672     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    5673     * </pre>
    5674     *
    5675     * @param str  the String to do overlaying in, may be null
    5676     * @param overlay  the String to overlay, may be null
    5677     * @param start  the position to start overlaying at
    5678     * @param end  the position to stop overlaying before
    5679     * @return overlayed String, {@code null} if null String input
    5680     * @since 2.0
    5681     */
    5682    public static String overlay(final String str, String overlay, int start, int end) {
    5683        if (str == null) {
    5684            return null;
    5685        }
    5686        if (overlay == null) {
    5687            overlay = EMPTY;
    5688        }
    5689        final int len = str.length();
    5690        if (start < 0) {
    5691            start = 0;
    5692        }
    5693        if (start > len) {
    5694            start = len;
    5695        }
    5696        if (end < 0) {
    5697            end = 0;
    5698        }
    5699        if (end > len) {
    5700            end = len;
    5701        }
    5702        if (start > end) {
    5703            final int temp = start;
    5704            start = end;
    5705            end = temp;
    5706        }
    5707        return str.substring(0, start) +
    5708            overlay +
    5709            str.substring(end);
    5710    }
    5711
    5712    /**
    5713     * Prepends the prefix to the start of the string if the string does not
    5714     * already start with any of the prefixes.
    5715     *
    5716     * @param str The string.
    5717     * @param prefix The prefix to prepend to the start of the string.
    5718     * @param ignoreCase Indicates whether the compare should ignore case.
    5719     * @param prefixes Additional prefixes that are valid (optional).
    5720     *
    5721     * @return A new String if prefix was prepended, the same string otherwise.
    5722     */
    5723    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
    5724        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
    5725            return str;
    5726        }
    5727        if (ArrayUtils.isNotEmpty(prefixes)) {
    5728            for (final CharSequence p : prefixes) {
    5729                if (startsWith(str, p, ignoreCase)) {
    5730                    return str;
    5731                }
    5732            }
    5733        }
    5734        return prefix + str;
    5735    }
    5736
    5737    /**
    5738     * Prepends the prefix to the start of the string if the string does not
    5739     * already start with any of the prefixes.
    5740     *
    5741     * <pre>
    5742     * StringUtils.prependIfMissing(null, null) = null
    5743     * StringUtils.prependIfMissing("abc", null) = "abc"
    5744     * StringUtils.prependIfMissing("", "xyz") = "xyz"
    5745     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
    5746     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
    5747     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
    5748     * </pre>
    5749     * <p>With additional prefixes,</p>
    5750     * <pre>
    5751     * StringUtils.prependIfMissing(null, null, null) = null
    5752     * StringUtils.prependIfMissing("abc", null, null) = "abc"
    5753     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
    5754     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5755     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
    5756     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
    5757     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
    5758     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
    5759     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
    5760     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
    5761     * </pre>
    5762     *
    5763     * @param str The string.
    5764     * @param prefix The prefix to prepend to the start of the string.
    5765     * @param prefixes Additional prefixes that are valid.
    5766     *
    5767     * @return A new String if prefix was prepended, the same string otherwise.
    5768     *
    5769     * @since 3.2
    5770     */
    5771    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5772        return prependIfMissing(str, prefix, false, prefixes);
    5773    }
    5774
    5775    /**
    5776     * Prepends the prefix to the start of the string if the string does not
    5777     * already start, case-insensitive, with any of the prefixes.
    5778     *
    5779     * <pre>
    5780     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
    5781     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
    5782     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
    5783     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
    5784     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
    5785     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
    5786     * </pre>
    5787     * <p>With additional prefixes,</p>
    5788     * <pre>
    5789     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
    5790     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
    5791     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
    5792     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    5793     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    5794     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
    5795     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
    5796     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
    5797     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
    5798     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
    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 (optional).
    5804     *
    5805     * @return A new String if prefix was prepended, the same string otherwise.
    5806     *
    5807     * @since 3.2
    5808     */
    5809    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    5810        return prependIfMissing(str, prefix, true, prefixes);
    5811    }
    5812
    5813    /**
    5814     * Removes all occurrences of a character from within the source string.
    5815     *
    5816     * <p>A {@code null} source string will return {@code null}.
    5817     * An empty ("") source string will return the empty string.</p>
    5818     *
    5819     * <pre>
    5820     * StringUtils.remove(null, *)       = null
    5821     * StringUtils.remove("", *)         = ""
    5822     * StringUtils.remove("queued", 'u') = "qeed"
    5823     * StringUtils.remove("queued", 'z') = "queued"
    5824     * </pre>
    5825     *
    5826     * @param str  the source String to search, may be null
    5827     * @param remove  the char to search for and remove, may be null
    5828     * @return the substring with the char removed if found,
    5829     *  {@code null} if null String input
    5830     * @since 2.1
    5831     */
    5832    public static String remove(final String str, final char remove) {
    5833        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    5834            return str;
    5835        }
    5836        final char[] chars = str.toCharArray();
    5837        int pos = 0;
    5838        for (int i = 0; i < chars.length; i++) {
    5839            if (chars[i] != remove) {
    5840                chars[pos++] = chars[i];
    5841            }
    5842        }
    5843        return new String(chars, 0, pos);
    5844    }
    5845
    5846    /**
    5847     * Removes all occurrences of a substring from within the source string.
    5848     *
    5849     * <p>A {@code null} source string will return {@code null}.
    5850     * An empty ("") source string will return the empty string.
    5851     * A {@code null} remove string will return the source string.
    5852     * An empty ("") remove string will return the source string.</p>
    5853     *
    5854     * <pre>
    5855     * StringUtils.remove(null, *)        = null
    5856     * StringUtils.remove("", *)          = ""
    5857     * StringUtils.remove(*, null)        = *
    5858     * StringUtils.remove(*, "")          = *
    5859     * StringUtils.remove("queued", "ue") = "qd"
    5860     * StringUtils.remove("queued", "zz") = "queued"
    5861     * </pre>
    5862     *
    5863     * @param str  the source String to search, may be null
    5864     * @param remove  the String to search for and remove, may be null
    5865     * @return the substring with the string removed if found,
    5866     *  {@code null} if null String input
    5867     * @since 2.1
    5868     */
    5869    public static String remove(final String str, final String remove) {
    5870        if (isEmpty(str) || isEmpty(remove)) {
    5871            return str;
    5872        }
    5873        return replace(str, remove, EMPTY, -1);
    5874    }
    5875
    5876    /**
    5877     * Removes each substring of the text String that matches the given regular expression.
    5878     *
    5879     * This method is a {@code null} safe equivalent to:
    5880     * <ul>
    5881     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
    5882     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
    5883     * </ul>
    5884     *
    5885     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5886     *
    5887     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
    5888     * is NOT automatically added.
    5889     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    5890     * DOTALL is also known as single-line mode in Perl.</p>
    5891     *
    5892     * <pre>
    5893     * StringUtils.removeAll(null, *)      = null
    5894     * StringUtils.removeAll("any", (String) null)  = "any"
    5895     * StringUtils.removeAll("any", "")    = "any"
    5896     * StringUtils.removeAll("any", ".*")  = ""
    5897     * StringUtils.removeAll("any", ".+")  = ""
    5898     * StringUtils.removeAll("abc", ".?")  = ""
    5899     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
    5900     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    5901     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
    5902     * </pre>
    5903     *
    5904     * @param text  text to remove from, may be null
    5905     * @param regex  the regular expression to which this string is to be matched
    5906     * @return  the text with any removes processed,
    5907     *              {@code null} if null String input
    5908     *
    5909     * @throws  java.util.regex.PatternSyntaxException
    5910     *              if the regular expression's syntax is invalid
    5911     *
    5912     * @see #replaceAll(String, String, String)
    5913     * @see #removePattern(String, String)
    5914     * @see String#replaceAll(String, String)
    5915     * @see java.util.regex.Pattern
    5916     * @see java.util.regex.Pattern#DOTALL
    5917     * @since 3.5
    5918     *
    5919     * @deprecated Moved to RegExUtils.
    5920     */
    5921    @Deprecated
    5922    public static String removeAll(final String text, final String regex) {
    5923        return RegExUtils.removeAll(text, regex);
    5924    }
    5925
    5926    /**
    5927     * Removes a substring only if it is at the end of a source string,
    5928     * otherwise returns the source string.
    5929     *
    5930     * <p>A {@code null} source string will return {@code null}.
    5931     * An empty ("") source string will return the empty string.
    5932     * A {@code null} search string will return the source string.</p>
    5933     *
    5934     * <pre>
    5935     * StringUtils.removeEnd(null, *)      = null
    5936     * StringUtils.removeEnd("", *)        = ""
    5937     * StringUtils.removeEnd(*, null)      = *
    5938     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    5939     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    5940     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    5941     * StringUtils.removeEnd("abc", "")    = "abc"
    5942     * </pre>
    5943     *
    5944     * @param str  the source String to search, may be null
    5945     * @param remove  the String to search for and remove, may be null
    5946     * @return the substring with the string removed if found,
    5947     *  {@code null} if null String input
    5948     * @since 2.1
    5949     */
    5950    public static String removeEnd(final String str, final String remove) {
    5951        if (isEmpty(str) || isEmpty(remove)) {
    5952            return str;
    5953        }
    5954        if (str.endsWith(remove)) {
    5955            return str.substring(0, str.length() - remove.length());
    5956        }
    5957        return str;
    5958    }
    5959
    5960    /**
    5961     * Case insensitive removal of a substring if it is at the end of a source string,
    5962     * otherwise returns the source string.
    5963     *
    5964     * <p>A {@code null} source string will return {@code null}.
    5965     * An empty ("") source string will return the empty string.
    5966     * A {@code null} search string will return the source string.</p>
    5967     *
    5968     * <pre>
    5969     * StringUtils.removeEndIgnoreCase(null, *)      = null
    5970     * StringUtils.removeEndIgnoreCase("", *)        = ""
    5971     * StringUtils.removeEndIgnoreCase(*, null)      = *
    5972     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    5973     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    5974     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    5975     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    5976     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    5977     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    5978     * </pre>
    5979     *
    5980     * @param str  the source String to search, may be null
    5981     * @param remove  the String to search for (case-insensitive) and remove, may be null
    5982     * @return the substring with the string removed if found,
    5983     *  {@code null} if null String input
    5984     * @since 2.4
    5985     */
    5986    public static String removeEndIgnoreCase(final String str, final String remove) {
    5987        if (isEmpty(str) || isEmpty(remove)) {
    5988            return str;
    5989        }
    5990        if (endsWithIgnoreCase(str, remove)) {
    5991            return str.substring(0, str.length() - remove.length());
    5992        }
    5993        return str;
    5994    }
    5995
    5996    /**
    5997     * Removes the first substring of the text string that matches the given regular expression.
    5998     *
    5999     * This method is a {@code null} safe equivalent to:
    6000     * <ul>
    6001     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
    6002     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
    6003     * </ul>
    6004     *
    6005     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6006     *
    6007     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    6008     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6009     * DOTALL is also known as single-line mode in Perl.</p>
    6010     *
    6011     * <pre>
    6012     * StringUtils.removeFirst(null, *)      = null
    6013     * StringUtils.removeFirst("any", (String) null)  = "any"
    6014     * StringUtils.removeFirst("any", "")    = "any"
    6015     * StringUtils.removeFirst("any", ".*")  = ""
    6016     * StringUtils.removeFirst("any", ".+")  = ""
    6017     * StringUtils.removeFirst("abc", ".?")  = "bc"
    6018     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
    6019     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    6020     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
    6021     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
    6022     * </pre>
    6023     *
    6024     * @param text  text to remove from, may be null
    6025     * @param regex  the regular expression to which this string is to be matched
    6026     * @return  the text with the first replacement processed,
    6027     *              {@code null} if null String input
    6028     *
    6029     * @throws  java.util.regex.PatternSyntaxException
    6030     *              if the regular expression's syntax is invalid
    6031     *
    6032     * @see #replaceFirst(String, String, String)
    6033     * @see String#replaceFirst(String, String)
    6034     * @see java.util.regex.Pattern
    6035     * @see java.util.regex.Pattern#DOTALL
    6036     * @since 3.5
    6037     *
    6038     * @deprecated Moved to RegExUtils.
    6039     */
    6040    @Deprecated
    6041    public static String removeFirst(final String text, final String regex) {
    6042        return replaceFirst(text, regex, EMPTY);
    6043    }
    6044
    6045    /**
    6046     * Case insensitive removal of all occurrences of a substring from within
    6047     * the source string.
    6048     *
    6049     * <p>
    6050     * A {@code null} source string will return {@code null}. An empty ("")
    6051     * source string will return the empty string. A {@code null} remove string
    6052     * will return the source string. An empty ("") remove string will return
    6053     * the source string.
    6054     * </p>
    6055     *
    6056     * <pre>
    6057     * StringUtils.removeIgnoreCase(null, *)        = null
    6058     * StringUtils.removeIgnoreCase("", *)          = ""
    6059     * StringUtils.removeIgnoreCase(*, null)        = *
    6060     * StringUtils.removeIgnoreCase(*, "")          = *
    6061     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
    6062     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
    6063     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
    6064     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
    6065     * </pre>
    6066     *
    6067     * @param str
    6068     *            the source String to search, may be null
    6069     * @param remove
    6070     *            the String to search for (case-insensitive) and remove, may be
    6071     *            null
    6072     * @return the substring with the string removed if found, {@code null} if
    6073     *         null String input
    6074     * @since 3.5
    6075     */
    6076    public static String removeIgnoreCase(final String str, final String remove) {
    6077        return replaceIgnoreCase(str, remove, EMPTY, -1);
    6078    }
    6079
    6080    /**
    6081     * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
    6082     *
    6083     * This call is a {@code null} safe equivalent to:
    6084     * <ul>
    6085     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
    6086     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
    6087     * </ul>
    6088     *
    6089     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6090     *
    6091     * <pre>
    6092     * StringUtils.removePattern(null, *)       = null
    6093     * StringUtils.removePattern("any", (String) null)   = "any"
    6094     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
    6095     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
    6096     * </pre>
    6097     *
    6098     * @param source
    6099     *            the source string
    6100     * @param regex
    6101     *            the regular expression to which this string is to be matched
    6102     * @return The resulting {@link String}
    6103     * @see #replacePattern(String, String, String)
    6104     * @see String#replaceAll(String, String)
    6105     * @see Pattern#DOTALL
    6106     * @since 3.2
    6107     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    6108     *
    6109     * @deprecated Moved to RegExUtils.
    6110     */
    6111    @Deprecated
    6112    public static String removePattern(final String source, final String regex) {
    6113        return RegExUtils.removePattern(source, regex);
    6114    }
    6115
    6116    /**
    6117     * Removes a char only if it is at the beginning of a source string,
    6118     * otherwise returns the source string.
    6119     *
    6120     * <p>A {@code null} source string will return {@code null}.
    6121     * An empty ("") source string will return the empty string.
    6122     * A {@code null} search char will return the source string.</p>
    6123     *
    6124     * <pre>
    6125     * StringUtils.removeStart(null, *)      = null
    6126     * StringUtils.removeStart("", *)        = ""
    6127     * StringUtils.removeStart(*, null)      = *
    6128     * StringUtils.removeStart("/path", '/') = "path"
    6129     * StringUtils.removeStart("path", '/')  = "path"
    6130     * StringUtils.removeStart("path", 0)    = "path"
    6131     * </pre>
    6132     *
    6133     * @param str  the source String to search, may be null.
    6134     * @param remove  the char to search for and remove.
    6135     * @return the substring with the char removed if found,
    6136     *  {@code null} if null String input.
    6137     * @since 3.13.0
    6138     */
    6139    public static String removeStart(final String str, final char remove) {
    6140        if (isEmpty(str)) {
    6141            return str;
    6142        }
    6143        return str.charAt(0) == remove ? str.substring(1) : str;
    6144    }
    6145
    6146    /**
    6147     * Removes a substring only if it is at the beginning of a source string,
    6148     * otherwise returns the source string.
    6149     *
    6150     * <p>A {@code null} source string will return {@code null}.
    6151     * An empty ("") source string will return the empty string.
    6152     * A {@code null} search string will return the source string.</p>
    6153     *
    6154     * <pre>
    6155     * StringUtils.removeStart(null, *)      = null
    6156     * StringUtils.removeStart("", *)        = ""
    6157     * StringUtils.removeStart(*, null)      = *
    6158     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    6159     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    6160     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    6161     * StringUtils.removeStart("abc", "")    = "abc"
    6162     * </pre>
    6163     *
    6164     * @param str  the source String to search, may be null
    6165     * @param remove  the String to search for and remove, may be null
    6166     * @return the substring with the string removed if found,
    6167     *  {@code null} if null String input
    6168     * @since 2.1
    6169     */
    6170    public static String removeStart(final String str, final String remove) {
    6171        if (isEmpty(str) || isEmpty(remove)) {
    6172            return str;
    6173        }
    6174        if (str.startsWith(remove)) {
    6175            return str.substring(remove.length());
    6176        }
    6177        return str;
    6178    }
    6179
    6180    /**
    6181     * Case insensitive removal of a substring if it is at the beginning of a source string,
    6182     * otherwise returns the source string.
    6183     *
    6184     * <p>A {@code null} source string will return {@code null}.
    6185     * An empty ("") source string will return the empty string.
    6186     * A {@code null} search string will return the source string.</p>
    6187     *
    6188     * <pre>
    6189     * StringUtils.removeStartIgnoreCase(null, *)      = null
    6190     * StringUtils.removeStartIgnoreCase("", *)        = ""
    6191     * StringUtils.removeStartIgnoreCase(*, null)      = *
    6192     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
    6193     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
    6194     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
    6195     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    6196     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
    6197     * </pre>
    6198     *
    6199     * @param str  the source String to search, may be null
    6200     * @param remove  the String to search for (case-insensitive) and remove, may be null
    6201     * @return the substring with the string removed if found,
    6202     *  {@code null} if null String input
    6203     * @since 2.4
    6204     */
    6205    public static String removeStartIgnoreCase(final String str, final String remove) {
    6206        if (str != null && startsWithIgnoreCase(str, remove)) {
    6207            return str.substring(length(remove));
    6208        }
    6209        return str;
    6210    }
    6211
    6212    /**
    6213     * Returns padding using the specified delimiter repeated
    6214     * to a given length.
    6215     *
    6216     * <pre>
    6217     * StringUtils.repeat('e', 0)  = ""
    6218     * StringUtils.repeat('e', 3)  = "eee"
    6219     * StringUtils.repeat('e', -2) = ""
    6220     * </pre>
    6221     *
    6222     * <p>Note: this method does not support padding with
    6223     * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    6224     * as they require a pair of {@code char}s to be represented.
    6225     * If you are needing to support full I18N of your applications
    6226     * consider using {@link #repeat(String, int)} instead.
    6227     * </p>
    6228     *
    6229     * @param ch  character to repeat
    6230     * @param repeat  number of times to repeat char, negative treated as zero
    6231     * @return String with repeated character
    6232     * @see #repeat(String, int)
    6233     */
    6234    public static String repeat(final char ch, final int repeat) {
    6235        if (repeat <= 0) {
    6236            return EMPTY;
    6237        }
    6238        return new String(ArrayFill.fill(new char[repeat], ch));
    6239    }
    6240
    6241    /**
    6242     * Repeat a String {@code repeat} times to form a
    6243     * new String.
    6244     *
    6245     * <pre>
    6246     * StringUtils.repeat(null, 2) = null
    6247     * StringUtils.repeat("", 0)   = ""
    6248     * StringUtils.repeat("", 2)   = ""
    6249     * StringUtils.repeat("a", 3)  = "aaa"
    6250     * StringUtils.repeat("ab", 2) = "abab"
    6251     * StringUtils.repeat("a", -2) = ""
    6252     * </pre>
    6253     *
    6254     * @param str  the String to repeat, may be null
    6255     * @param repeat  number of times to repeat str, negative treated as zero
    6256     * @return a new String consisting of the original String repeated,
    6257     *  {@code null} if null String input
    6258     */
    6259    public static String repeat(final String str, final int repeat) {
    6260        // Performance tuned for 2.0 (JDK1.4)
    6261        if (str == null) {
    6262            return null;
    6263        }
    6264        if (repeat <= 0) {
    6265            return EMPTY;
    6266        }
    6267        final int inputLength = str.length();
    6268        if (repeat == 1 || inputLength == 0) {
    6269            return str;
    6270        }
    6271        if (inputLength == 1 && repeat <= PAD_LIMIT) {
    6272            return repeat(str.charAt(0), repeat);
    6273        }
    6274
    6275        final int outputLength = inputLength * repeat;
    6276        switch (inputLength) {
    6277            case 1 :
    6278                return repeat(str.charAt(0), repeat);
    6279            case 2 :
    6280                final char ch0 = str.charAt(0);
    6281                final char ch1 = str.charAt(1);
    6282                final char[] output2 = new char[outputLength];
    6283                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
    6284                    output2[i] = ch0;
    6285                    output2[i + 1] = ch1;
    6286                }
    6287                return new String(output2);
    6288            default :
    6289                final StringBuilder buf = new StringBuilder(outputLength);
    6290                for (int i = 0; i < repeat; i++) {
    6291                    buf.append(str);
    6292                }
    6293                return buf.toString();
    6294        }
    6295    }
    6296
    6297    /**
    6298     * Repeat a String {@code repeat} times to form a
    6299     * new String, with a String separator injected each time.
    6300     *
    6301     * <pre>
    6302     * StringUtils.repeat(null, null, 2) = null
    6303     * StringUtils.repeat(null, "x", 2)  = null
    6304     * StringUtils.repeat("", null, 0)   = ""
    6305     * StringUtils.repeat("", "", 2)     = ""
    6306     * StringUtils.repeat("", "x", 3)    = "xx"
    6307     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    6308     * </pre>
    6309     *
    6310     * @param str        the String to repeat, may be null
    6311     * @param separator  the String to inject, may be null
    6312     * @param repeat     number of times to repeat str, negative treated as zero
    6313     * @return a new String consisting of the original String repeated,
    6314     *  {@code null} if null String input
    6315     * @since 2.5
    6316     */
    6317    public static String repeat(final String str, final String separator, final int repeat) {
    6318        if (str == null || separator == null) {
    6319            return repeat(str, repeat);
    6320        }
    6321        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    6322        final String result = repeat(str + separator, repeat);
    6323        return removeEnd(result, separator);
    6324    }
    6325
    6326    /**
    6327     * Replaces all occurrences of a String within another String.
    6328     *
    6329     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6330     *
    6331     * <pre>
    6332     * StringUtils.replace(null, *, *)        = null
    6333     * StringUtils.replace("", *, *)          = ""
    6334     * StringUtils.replace("any", null, *)    = "any"
    6335     * StringUtils.replace("any", *, null)    = "any"
    6336     * StringUtils.replace("any", "", *)      = "any"
    6337     * StringUtils.replace("aba", "a", null)  = "aba"
    6338     * StringUtils.replace("aba", "a", "")    = "b"
    6339     * StringUtils.replace("aba", "a", "z")   = "zbz"
    6340     * </pre>
    6341     *
    6342     * @see #replace(String text, String searchString, String replacement, int max)
    6343     * @param text  text to search and replace in, may be null
    6344     * @param searchString  the String to search for, may be null
    6345     * @param replacement  the String to replace it with, may be null
    6346     * @return the text with any replacements processed,
    6347     *  {@code null} if null String input
    6348     */
    6349    public static String replace(final String text, final String searchString, final String replacement) {
    6350        return replace(text, searchString, replacement, -1);
    6351    }
    6352
    6353    /**
    6354     * Replaces a String with another String inside a larger String,
    6355     * for the first {@code max} values of the search String.
    6356     *
    6357     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6358     *
    6359     * <pre>
    6360     * StringUtils.replace(null, *, *, *)         = null
    6361     * StringUtils.replace("", *, *, *)           = ""
    6362     * StringUtils.replace("any", null, *, *)     = "any"
    6363     * StringUtils.replace("any", *, null, *)     = "any"
    6364     * StringUtils.replace("any", "", *, *)       = "any"
    6365     * StringUtils.replace("any", *, *, 0)        = "any"
    6366     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    6367     * StringUtils.replace("abaa", "a", "", -1)   = "b"
    6368     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    6369     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    6370     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    6371     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    6372     * </pre>
    6373     *
    6374     * @param text  text to search and replace in, may be null
    6375     * @param searchString  the String to search for, may be null
    6376     * @param replacement  the String to replace it with, may be null
    6377     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6378     * @return the text with any replacements processed,
    6379     *  {@code null} if null String input
    6380     */
    6381    public static String replace(final String text, final String searchString, final String replacement, final int max) {
    6382        return replace(text, searchString, replacement, max, false);
    6383    }
    6384
    6385    /**
    6386     * Replaces a String with another String inside a larger String,
    6387     * for the first {@code max} values of the search String,
    6388     * case-sensitively/insensitively based on {@code ignoreCase} value.
    6389     *
    6390     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6391     *
    6392     * <pre>
    6393     * StringUtils.replace(null, *, *, *, false)         = null
    6394     * StringUtils.replace("", *, *, *, false)           = ""
    6395     * StringUtils.replace("any", null, *, *, false)     = "any"
    6396     * StringUtils.replace("any", *, null, *, false)     = "any"
    6397     * StringUtils.replace("any", "", *, *, false)       = "any"
    6398     * StringUtils.replace("any", *, *, 0, false)        = "any"
    6399     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
    6400     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
    6401     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
    6402     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
    6403     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
    6404     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
    6405     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
    6406     * </pre>
    6407     *
    6408     * @param text  text to search and replace in, may be null
    6409     * @param searchString  the String to search for (case-insensitive), may be null
    6410     * @param replacement  the String to replace it with, may be null
    6411     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6412     * @param ignoreCase if true replace is case-insensitive, otherwise case-sensitive
    6413     * @return the text with any replacements processed,
    6414     *  {@code null} if null String input
    6415     */
    6416     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
    6417         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
    6418             return text;
    6419         }
    6420         if (ignoreCase) {
    6421             searchString = searchString.toLowerCase();
    6422         }
    6423         int start = 0;
    6424         int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
    6425         if (end == INDEX_NOT_FOUND) {
    6426             return text;
    6427         }
    6428         final int replLength = searchString.length();
    6429         int increase = Math.max(replacement.length() - replLength, 0);
    6430         increase *= max < 0 ? 16 : Math.min(max, 64);
    6431         final StringBuilder buf = new StringBuilder(text.length() + increase);
    6432         while (end != INDEX_NOT_FOUND) {
    6433             buf.append(text, start, end).append(replacement);
    6434             start = end + replLength;
    6435             if (--max == 0) {
    6436                 break;
    6437             }
    6438             end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
    6439         }
    6440         buf.append(text, start, text.length());
    6441         return buf.toString();
    6442     }
    6443
    6444    /**
    6445     * Replaces each substring of the text String that matches the given regular expression
    6446     * with the given replacement.
    6447     *
    6448     * This method is a {@code null} safe equivalent to:
    6449     * <ul>
    6450     *  <li>{@code text.replaceAll(regex, replacement)}</li>
    6451     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
    6452     * </ul>
    6453     *
    6454     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6455     *
    6456     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
    6457     * is NOT automatically added.
    6458     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6459     * DOTALL is also known as single-line mode in Perl.</p>
    6460     *
    6461     * <pre>
    6462     * StringUtils.replaceAll(null, *, *)       = null
    6463     * StringUtils.replaceAll("any", (String) null, *)   = "any"
    6464     * StringUtils.replaceAll("any", *, null)   = "any"
    6465     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
    6466     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
    6467     * StringUtils.replaceAll("", ".+", "zzz")  = ""
    6468     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
    6469     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
    6470     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    6471     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
    6472     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    6473     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    6474     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    6475     * </pre>
    6476     *
    6477     * @param text  text to search and replace in, may be null
    6478     * @param regex  the regular expression to which this string is to be matched
    6479     * @param replacement  the string to be substituted for each match
    6480     * @return  the text with any replacements processed,
    6481     *              {@code null} if null String input
    6482     *
    6483     * @throws  java.util.regex.PatternSyntaxException
    6484     *              if the regular expression's syntax is invalid
    6485     *
    6486     * @see #replacePattern(String, String, String)
    6487     * @see String#replaceAll(String, String)
    6488     * @see java.util.regex.Pattern
    6489     * @see java.util.regex.Pattern#DOTALL
    6490     * @since 3.5
    6491     *
    6492     * @deprecated Moved to RegExUtils.
    6493     */
    6494    @Deprecated
    6495    public static String replaceAll(final String text, final String regex, final String replacement) {
    6496        return RegExUtils.replaceAll(text, regex, replacement);
    6497    }
    6498
    6499    /**
    6500     * Replaces all occurrences of a character in a String with another.
    6501     * This is a null-safe version of {@link String#replace(char, char)}.
    6502     *
    6503     * <p>A {@code null} string input returns {@code null}.
    6504     * An empty ("") string input returns an empty string.</p>
    6505     *
    6506     * <pre>
    6507     * StringUtils.replaceChars(null, *, *)        = null
    6508     * StringUtils.replaceChars("", *, *)          = ""
    6509     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    6510     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    6511     * </pre>
    6512     *
    6513     * @param str  String to replace characters in, may be null
    6514     * @param searchChar  the character to search for, may be null
    6515     * @param replaceChar  the character to replace, may be null
    6516     * @return modified String, {@code null} if null string input
    6517     * @since 2.0
    6518     */
    6519    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
    6520        if (str == null) {
    6521            return null;
    6522        }
    6523        return str.replace(searchChar, replaceChar);
    6524    }
    6525
    6526    /**
    6527     * Replaces multiple characters in a String in one go.
    6528     * This method can also be used to delete characters.
    6529     *
    6530     * <p>For example:<br>
    6531     * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
    6532     *
    6533     * <p>A {@code null} string input returns {@code null}.
    6534     * An empty ("") string input returns an empty string.
    6535     * A null or empty set of search characters returns the input string.</p>
    6536     *
    6537     * <p>The length of the search characters should normally equal the length
    6538     * of the replace characters.
    6539     * If the search characters is longer, then the extra search characters
    6540     * are deleted.
    6541     * If the search characters is shorter, then the extra replace characters
    6542     * are ignored.</p>
    6543     *
    6544     * <pre>
    6545     * StringUtils.replaceChars(null, *, *)           = null
    6546     * StringUtils.replaceChars("", *, *)             = ""
    6547     * StringUtils.replaceChars("abc", null, *)       = "abc"
    6548     * StringUtils.replaceChars("abc", "", *)         = "abc"
    6549     * StringUtils.replaceChars("abc", "b", null)     = "ac"
    6550     * StringUtils.replaceChars("abc", "b", "")       = "ac"
    6551     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    6552     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    6553     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    6554     * </pre>
    6555     *
    6556     * @param str  String to replace characters in, may be null
    6557     * @param searchChars  a set of characters to search for, may be null
    6558     * @param replaceChars  a set of characters to replace, may be null
    6559     * @return modified String, {@code null} if null string input
    6560     * @since 2.0
    6561     */
    6562    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
    6563        if (isEmpty(str) || isEmpty(searchChars)) {
    6564            return str;
    6565        }
    6566        if (replaceChars == null) {
    6567            replaceChars = EMPTY;
    6568        }
    6569        boolean modified = false;
    6570        final int replaceCharsLength = replaceChars.length();
    6571        final int strLength = str.length();
    6572        final StringBuilder buf = new StringBuilder(strLength);
    6573        for (int i = 0; i < strLength; i++) {
    6574            final char ch = str.charAt(i);
    6575            final int index = searchChars.indexOf(ch);
    6576            if (index >= 0) {
    6577                modified = true;
    6578                if (index < replaceCharsLength) {
    6579                    buf.append(replaceChars.charAt(index));
    6580                }
    6581            } else {
    6582                buf.append(ch);
    6583            }
    6584        }
    6585        if (modified) {
    6586            return buf.toString();
    6587        }
    6588        return str;
    6589    }
    6590
    6591    /**
    6592     * Replaces all occurrences of Strings within another String.
    6593     *
    6594     * <p>
    6595     * A {@code null} reference passed to this method is a no-op, or if
    6596     * any "search string" or "string to replace" is null, that replace will be
    6597     * ignored. This will not repeat. For repeating replaces, call the
    6598     * overloaded method.
    6599     * </p>
    6600     *
    6601     * <pre>
    6602     *  StringUtils.replaceEach(null, *, *)        = null
    6603     *  StringUtils.replaceEach("", *, *)          = ""
    6604     *  StringUtils.replaceEach("aba", null, null) = "aba"
    6605     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
    6606     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
    6607     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
    6608     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
    6609     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
    6610     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    6611     *  (example of how it does not repeat)
    6612     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    6613     * </pre>
    6614     *
    6615     * @param text
    6616     *            text to search and replace in, no-op if null
    6617     * @param searchList
    6618     *            the Strings to search for, no-op if null
    6619     * @param replacementList
    6620     *            the Strings to replace them with, no-op if null
    6621     * @return the text with any replacements processed, {@code null} if
    6622     *         null String input
    6623     * @throws IllegalArgumentException
    6624     *             if the lengths of the arrays are not the same (null is ok,
    6625     *             and/or size 0)
    6626     * @since 2.4
    6627     */
    6628    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
    6629        return replaceEach(text, searchList, replacementList, false, 0);
    6630    }
    6631
    6632    /**
    6633     * Replace all occurrences of Strings within another String.
    6634     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
    6635     * {@link #replaceEach(String, String[], String[])}
    6636     *
    6637     * <p>
    6638     * A {@code null} reference passed to this method is a no-op, or if
    6639     * any "search string" or "string to replace" is null, that replace will be
    6640     * ignored.
    6641     * </p>
    6642     *
    6643     * <pre>
    6644     *  StringUtils.replaceEach(null, *, *, *, *) = null
    6645     *  StringUtils.replaceEach("", *, *, *, *) = ""
    6646     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
    6647     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
    6648     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
    6649     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
    6650     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
    6651     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
    6652     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
    6653     *  (example of how it repeats)
    6654     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
    6655     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
    6656     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
    6657     * </pre>
    6658     *
    6659     * @param text
    6660     *            text to search and replace in, no-op if null
    6661     * @param searchList
    6662     *            the Strings to search for, no-op if null
    6663     * @param replacementList
    6664     *            the Strings to replace them with, no-op if null
    6665     * @param repeat if true, then replace repeatedly
    6666     *       until there are no more possible replacements or timeToLive < 0
    6667     * @param timeToLive
    6668     *            if less than 0 then there is a circular reference and endless
    6669     *            loop
    6670     * @return the text with any replacements processed, {@code null} if
    6671     *         null String input
    6672     * @throws IllegalStateException
    6673     *             if the search is repeating and there is an endless loop due
    6674     *             to outputs of one being inputs to another
    6675     * @throws IllegalArgumentException
    6676     *             if the lengths of the arrays are not the same (null is ok,
    6677     *             and/or size 0)
    6678     * @since 2.4
    6679     */
    6680    private static String replaceEach(
    6681            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
    6682
    6683        // mchyzer Performance note: This creates very few new objects (one major goal)
    6684        // let me know if there are performance requests, we can create a harness to measure
    6685
    6686        // if recursing, this shouldn't be less than 0
    6687        if (timeToLive < 0) {
    6688            final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
    6689            final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
    6690            searchSet.retainAll(replacementSet);
    6691            if (!searchSet.isEmpty()) {
    6692                throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
    6693                        "output of one loop is the input of another");
    6694            }
    6695        }
    6696
    6697        if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || ArrayUtils.isNotEmpty(searchList) && timeToLive == -1) {
    6698            return text;
    6699        }
    6700
    6701        final int searchLength = searchList.length;
    6702        final int replacementLength = replacementList.length;
    6703
    6704        // make sure lengths are ok, these need to be equal
    6705        if (searchLength != replacementLength) {
    6706            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    6707                + searchLength
    6708                + " vs "
    6709                + replacementLength);
    6710        }
    6711
    6712        // keep track of which still have matches
    6713        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    6714
    6715        // index on index that the match was found
    6716        int textIndex = -1;
    6717        int replaceIndex = -1;
    6718        int tempIndex;
    6719
    6720        // index of replace array that will replace the search string found
    6721        // NOTE: logic duplicated below START
    6722        for (int i = 0; i < searchLength; i++) {
    6723            if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6724                continue;
    6725            }
    6726            tempIndex = text.indexOf(searchList[i]);
    6727
    6728            // see if we need to keep searching for this
    6729            if (tempIndex == -1) {
    6730                noMoreMatchesForReplIndex[i] = true;
    6731            } else if (textIndex == -1 || tempIndex < textIndex) {
    6732                textIndex = tempIndex;
    6733                replaceIndex = i;
    6734            }
    6735        }
    6736        // NOTE: logic mostly below END
    6737
    6738        // no search strings found, we are done
    6739        if (textIndex == -1) {
    6740            return text;
    6741        }
    6742
    6743        int start = 0;
    6744
    6745        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
    6746        int increase = 0;
    6747
    6748        // count the replacement text elements that are larger than their corresponding text being replaced
    6749        for (int i = 0; i < searchList.length; i++) {
    6750            if (searchList[i] == null || replacementList[i] == null) {
    6751                continue;
    6752            }
    6753            final int greater = replacementList[i].length() - searchList[i].length();
    6754            if (greater > 0) {
    6755                increase += 3 * greater; // assume 3 matches
    6756            }
    6757        }
    6758        // have upper-bound at 20% increase, then let Java take over
    6759        increase = Math.min(increase, text.length() / 5);
    6760
    6761        final StringBuilder buf = new StringBuilder(text.length() + increase);
    6762
    6763        while (textIndex != -1) {
    6764
    6765            for (int i = start; i < textIndex; i++) {
    6766                buf.append(text.charAt(i));
    6767            }
    6768            buf.append(replacementList[replaceIndex]);
    6769
    6770            start = textIndex + searchList[replaceIndex].length();
    6771
    6772            textIndex = -1;
    6773            replaceIndex = -1;
    6774            // find the next earliest match
    6775            // NOTE: logic mostly duplicated above START
    6776            for (int i = 0; i < searchLength; i++) {
    6777                if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
    6778                    continue;
    6779                }
    6780                tempIndex = text.indexOf(searchList[i], start);
    6781
    6782                // see if we need to keep searching for this
    6783                if (tempIndex == -1) {
    6784                    noMoreMatchesForReplIndex[i] = true;
    6785                } else if (textIndex == -1 || tempIndex < textIndex) {
    6786                    textIndex = tempIndex;
    6787                    replaceIndex = i;
    6788                }
    6789            }
    6790            // NOTE: logic duplicated above END
    6791
    6792        }
    6793        final int textLength = text.length();
    6794        for (int i = start; i < textLength; i++) {
    6795            buf.append(text.charAt(i));
    6796        }
    6797        final String result = buf.toString();
    6798        if (!repeat) {
    6799            return result;
    6800        }
    6801
    6802        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    6803    }
    6804
    6805    /**
    6806     * Replaces all occurrences of Strings within another String.
    6807     *
    6808     * <p>
    6809     * A {@code null} reference passed to this method is a no-op, or if
    6810     * any "search string" or "string to replace" is null, that replace will be
    6811     * ignored.
    6812     * </p>
    6813     *
    6814     * <pre>
    6815     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
    6816     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
    6817     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
    6818     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
    6819     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
    6820     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
    6821     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
    6822     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
    6823     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
    6824     *  (example of how it repeats)
    6825     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
    6826     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
    6827     * </pre>
    6828     *
    6829     * @param text
    6830     *            text to search and replace in, no-op if null
    6831     * @param searchList
    6832     *            the Strings to search for, no-op if null
    6833     * @param replacementList
    6834     *            the Strings to replace them with, no-op if null
    6835     * @return the text with any replacements processed, {@code null} if
    6836     *         null String input
    6837     * @throws IllegalStateException
    6838     *             if the search is repeating and there is an endless loop due
    6839     *             to outputs of one being inputs to another
    6840     * @throws IllegalArgumentException
    6841     *             if the lengths of the arrays are not the same (null is ok,
    6842     *             and/or size 0)
    6843     * @since 2.4
    6844     */
    6845    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
    6846        return replaceEach(text, searchList, replacementList, true, ArrayUtils.getLength(searchList));
    6847    }
    6848
    6849    /**
    6850     * Replaces the first substring of the text string that matches the given regular expression
    6851     * with the given replacement.
    6852     *
    6853     * This method is a {@code null} safe equivalent to:
    6854     * <ul>
    6855     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
    6856     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
    6857     * </ul>
    6858     *
    6859     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6860     *
    6861     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    6862     * To use the DOTALL option prepend {@code "(?s)"} to the regex.
    6863     * DOTALL is also known as single-line mode in Perl.</p>
    6864     *
    6865     * <pre>
    6866     * StringUtils.replaceFirst(null, *, *)       = null
    6867     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
    6868     * StringUtils.replaceFirst("any", *, null)   = "any"
    6869     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
    6870     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
    6871     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
    6872     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
    6873     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
    6874     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    6875     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
    6876     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
    6877     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
    6878     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
    6879     * </pre>
    6880     *
    6881     * @param text  text to search and replace in, may be null
    6882     * @param regex  the regular expression to which this string is to be matched
    6883     * @param replacement  the string to be substituted for the first match
    6884     * @return  the text with the first replacement processed,
    6885     *              {@code null} if null String input
    6886     *
    6887     * @throws  java.util.regex.PatternSyntaxException
    6888     *              if the regular expression's syntax is invalid
    6889     *
    6890     * @see String#replaceFirst(String, String)
    6891     * @see java.util.regex.Pattern
    6892     * @see java.util.regex.Pattern#DOTALL
    6893     * @since 3.5
    6894     *
    6895     * @deprecated Moved to RegExUtils.
    6896     */
    6897    @Deprecated
    6898    public static String replaceFirst(final String text, final String regex, final String replacement) {
    6899        return RegExUtils.replaceFirst(text, regex, replacement);
    6900    }
    6901
    6902    /**
    6903     * Case insensitively replaces all occurrences of a String within another String.
    6904     *
    6905     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6906     *
    6907     * <pre>
    6908     * StringUtils.replaceIgnoreCase(null, *, *)        = null
    6909     * StringUtils.replaceIgnoreCase("", *, *)          = ""
    6910     * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
    6911     * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
    6912     * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
    6913     * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
    6914     * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
    6915     * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
    6916     * </pre>
    6917     *
    6918     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    6919     * @param text  text to search and replace in, may be null
    6920     * @param searchString  the String to search for (case-insensitive), may be null
    6921     * @param replacement  the String to replace it with, may be null
    6922     * @return the text with any replacements processed,
    6923     *  {@code null} if null String input
    6924     * @since 3.5
    6925     */
    6926     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
    6927         return replaceIgnoreCase(text, searchString, replacement, -1);
    6928     }
    6929
    6930    /**
    6931     * Case insensitively replaces a String with another String inside a larger String,
    6932     * for the first {@code max} values of the search String.
    6933     *
    6934     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6935     *
    6936     * <pre>
    6937     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
    6938     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
    6939     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
    6940     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
    6941     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
    6942     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
    6943     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
    6944     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
    6945     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
    6946     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
    6947     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
    6948     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
    6949     * </pre>
    6950     *
    6951     * @param text  text to search and replace in, may be null
    6952     * @param searchString  the String to search for (case-insensitive), may be null
    6953     * @param replacement  the String to replace it with, may be null
    6954     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    6955     * @return the text with any replacements processed,
    6956     *  {@code null} if null String input
    6957     * @since 3.5
    6958     */
    6959    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
    6960        return replace(text, searchString, replacement, max, true);
    6961    }
    6962
    6963    /**
    6964     * Replaces a String with another String inside a larger String, once.
    6965     *
    6966     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6967     *
    6968     * <pre>
    6969     * StringUtils.replaceOnce(null, *, *)        = null
    6970     * StringUtils.replaceOnce("", *, *)          = ""
    6971     * StringUtils.replaceOnce("any", null, *)    = "any"
    6972     * StringUtils.replaceOnce("any", *, null)    = "any"
    6973     * StringUtils.replaceOnce("any", "", *)      = "any"
    6974     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    6975     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    6976     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    6977     * </pre>
    6978     *
    6979     * @see #replace(String text, String searchString, String replacement, int max)
    6980     * @param text  text to search and replace in, may be null
    6981     * @param searchString  the String to search for, may be null
    6982     * @param replacement  the String to replace with, may be null
    6983     * @return the text with any replacements processed,
    6984     *  {@code null} if null String input
    6985     */
    6986    public static String replaceOnce(final String text, final String searchString, final String replacement) {
    6987        return replace(text, searchString, replacement, 1);
    6988    }
    6989
    6990    /**
    6991     * Case insensitively replaces a String with another String inside a larger String, once.
    6992     *
    6993     * <p>A {@code null} reference passed to this method is a no-op.</p>
    6994     *
    6995     * <pre>
    6996     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
    6997     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
    6998     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
    6999     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
    7000     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
    7001     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
    7002     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
    7003     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
    7004     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
    7005     * </pre>
    7006     *
    7007     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    7008     * @param text  text to search and replace in, may be null
    7009     * @param searchString  the String to search for (case-insensitive), may be null
    7010     * @param replacement  the String to replace with, may be null
    7011     * @return the text with any replacements processed,
    7012     *  {@code null} if null String input
    7013     * @since 3.5
    7014     */
    7015    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
    7016        return replaceIgnoreCase(text, searchString, replacement, 1);
    7017    }
    7018
    7019    /**
    7020     * Replaces each substring of the source String that matches the given regular expression with the given
    7021     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
    7022     *
    7023     * This call is a {@code null} safe equivalent to:
    7024     * <ul>
    7025     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
    7026     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
    7027     * </ul>
    7028     *
    7029     * <p>A {@code null} reference passed to this method is a no-op.</p>
    7030     *
    7031     * <pre>
    7032     * StringUtils.replacePattern(null, *, *)       = null
    7033     * StringUtils.replacePattern("any", (String) null, *)   = "any"
    7034     * StringUtils.replacePattern("any", *, null)   = "any"
    7035     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
    7036     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
    7037     * StringUtils.replacePattern("", ".+", "zzz")  = ""
    7038     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
    7039     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
    7040     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    7041     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    7042     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    7043     * </pre>
    7044     *
    7045     * @param source
    7046     *            the source string
    7047     * @param regex
    7048     *            the regular expression to which this string is to be matched
    7049     * @param replacement
    7050     *            the string to be substituted for each match
    7051     * @return The resulting {@link String}
    7052     * @see #replaceAll(String, String, String)
    7053     * @see String#replaceAll(String, String)
    7054     * @see Pattern#DOTALL
    7055     * @since 3.2
    7056     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    7057     *
    7058     * @deprecated Moved to RegExUtils.
    7059     */
    7060    @Deprecated
    7061    public static String replacePattern(final String source, final String regex, final String replacement) {
    7062        return RegExUtils.replacePattern(source, regex, replacement);
    7063    }
    7064
    7065    /**
    7066     * Reverses a String as per {@link StringBuilder#reverse()}.
    7067     *
    7068     * <p>A {@code null} String returns {@code null}.</p>
    7069     *
    7070     * <pre>
    7071     * StringUtils.reverse(null)  = null
    7072     * StringUtils.reverse("")    = ""
    7073     * StringUtils.reverse("bat") = "tab"
    7074     * </pre>
    7075     *
    7076     * @param str  the String to reverse, may be null
    7077     * @return the reversed String, {@code null} if null String input
    7078     */
    7079    public static String reverse(final String str) {
    7080        if (str == null) {
    7081            return null;
    7082        }
    7083        return new StringBuilder(str).reverse().toString();
    7084    }
    7085
    7086    /**
    7087     * Reverses a String that is delimited by a specific character.
    7088     *
    7089     * <p>The Strings between the delimiters are not reversed.
    7090     * Thus java.lang.String becomes String.lang.java (if the delimiter
    7091     * is {@code '.'}).</p>
    7092     *
    7093     * <pre>
    7094     * StringUtils.reverseDelimited(null, *)      = null
    7095     * StringUtils.reverseDelimited("", *)        = ""
    7096     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    7097     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    7098     * </pre>
    7099     *
    7100     * @param str  the String to reverse, may be null
    7101     * @param separatorChar  the separator character to use
    7102     * @return the reversed String, {@code null} if null String input
    7103     * @since 2.0
    7104     */
    7105    public static String reverseDelimited(final String str, final char separatorChar) {
    7106        final String[] strs = split(str, separatorChar);
    7107        ArrayUtils.reverse(strs);
    7108        return join(strs, separatorChar);
    7109    }
    7110
    7111    /**
    7112     * Gets the rightmost {@code len} characters of a String.
    7113     *
    7114     * <p>If {@code len} characters are not available, or the String
    7115     * is {@code null}, the String will be returned without an
    7116     * an exception. An empty String is returned if len is negative.</p>
    7117     *
    7118     * <pre>
    7119     * StringUtils.right(null, *)    = null
    7120     * StringUtils.right(*, -ve)     = ""
    7121     * StringUtils.right("", *)      = ""
    7122     * StringUtils.right("abc", 0)   = ""
    7123     * StringUtils.right("abc", 2)   = "bc"
    7124     * StringUtils.right("abc", 4)   = "abc"
    7125     * </pre>
    7126     *
    7127     * @param str  the String to get the rightmost characters from, may be null
    7128     * @param len  the length of the required String
    7129     * @return the rightmost characters, {@code null} if null String input
    7130     */
    7131    public static String right(final String str, final int len) {
    7132        if (str == null) {
    7133            return null;
    7134        }
    7135        if (len < 0) {
    7136            return EMPTY;
    7137        }
    7138        if (str.length() <= len) {
    7139            return str;
    7140        }
    7141        return str.substring(str.length() - len);
    7142    }
    7143
    7144    /**
    7145     * Right pad a String with spaces (' ').
    7146     *
    7147     * <p>The String is padded to the size of {@code size}.</p>
    7148     *
    7149     * <pre>
    7150     * StringUtils.rightPad(null, *)   = null
    7151     * StringUtils.rightPad("", 3)     = "   "
    7152     * StringUtils.rightPad("bat", 3)  = "bat"
    7153     * StringUtils.rightPad("bat", 5)  = "bat  "
    7154     * StringUtils.rightPad("bat", 1)  = "bat"
    7155     * StringUtils.rightPad("bat", -1) = "bat"
    7156     * </pre>
    7157     *
    7158     * @param str  the String to pad out, may be null
    7159     * @param size  the size to pad to
    7160     * @return right padded String or original String if no padding is necessary,
    7161     *  {@code null} if null String input
    7162     */
    7163    public static String rightPad(final String str, final int size) {
    7164        return rightPad(str, size, ' ');
    7165    }
    7166
    7167    /**
    7168     * Right pad a String with a specified character.
    7169     *
    7170     * <p>The String is padded to the size of {@code size}.</p>
    7171     *
    7172     * <pre>
    7173     * StringUtils.rightPad(null, *, *)     = null
    7174     * StringUtils.rightPad("", 3, 'z')     = "zzz"
    7175     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    7176     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    7177     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    7178     * StringUtils.rightPad("bat", -1, 'z') = "bat"
    7179     * </pre>
    7180     *
    7181     * @param str  the String to pad out, may be null
    7182     * @param size  the size to pad to
    7183     * @param padChar  the character to pad with
    7184     * @return right padded String or original String if no padding is necessary,
    7185     *  {@code null} if null String input
    7186     * @since 2.0
    7187     */
    7188    public static String rightPad(final String str, final int size, final char padChar) {
    7189        if (str == null) {
    7190            return null;
    7191        }
    7192        final int pads = size - str.length();
    7193        if (pads <= 0) {
    7194            return str; // returns original String when possible
    7195        }
    7196        if (pads > PAD_LIMIT) {
    7197            return rightPad(str, size, String.valueOf(padChar));
    7198        }
    7199        return str.concat(repeat(padChar, pads));
    7200    }
    7201
    7202    /**
    7203     * Right pad a String with a specified String.
    7204     *
    7205     * <p>The String is padded to the size of {@code size}.</p>
    7206     *
    7207     * <pre>
    7208     * StringUtils.rightPad(null, *, *)      = null
    7209     * StringUtils.rightPad("", 3, "z")      = "zzz"
    7210     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    7211     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    7212     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    7213     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    7214     * StringUtils.rightPad("bat", -1, "yz") = "bat"
    7215     * StringUtils.rightPad("bat", 5, null)  = "bat  "
    7216     * StringUtils.rightPad("bat", 5, "")    = "bat  "
    7217     * </pre>
    7218     *
    7219     * @param str  the String to pad out, may be null
    7220     * @param size  the size to pad to
    7221     * @param padStr  the String to pad with, null or empty treated as single space
    7222     * @return right padded String or original String if no padding is necessary,
    7223     *  {@code null} if null String input
    7224     */
    7225    public static String rightPad(final String str, final int size, String padStr) {
    7226        if (str == null) {
    7227            return null;
    7228        }
    7229        if (isEmpty(padStr)) {
    7230            padStr = SPACE;
    7231        }
    7232        final int padLen = padStr.length();
    7233        final int strLen = str.length();
    7234        final int pads = size - strLen;
    7235        if (pads <= 0) {
    7236            return str; // returns original String when possible
    7237        }
    7238        if (padLen == 1 && pads <= PAD_LIMIT) {
    7239            return rightPad(str, size, padStr.charAt(0));
    7240        }
    7241
    7242        if (pads == padLen) {
    7243            return str.concat(padStr);
    7244        }
    7245        if (pads < padLen) {
    7246            return str.concat(padStr.substring(0, pads));
    7247        }
    7248        final char[] padding = new char[pads];
    7249        final char[] padChars = padStr.toCharArray();
    7250        for (int i = 0; i < pads; i++) {
    7251            padding[i] = padChars[i % padLen];
    7252        }
    7253        return str.concat(new String(padding));
    7254    }
    7255
    7256    /**
    7257     * Rotate (circular shift) a String of {@code shift} characters.
    7258     * <ul>
    7259     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
    7260     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
    7261     * </ul>
    7262     *
    7263     * <pre>
    7264     * StringUtils.rotate(null, *)        = null
    7265     * StringUtils.rotate("", *)          = ""
    7266     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
    7267     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
    7268     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
    7269     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
    7270     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
    7271     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
    7272     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
    7273     * </pre>
    7274     *
    7275     * @param str  the String to rotate, may be null
    7276     * @param shift  number of time to shift (positive : right shift, negative : left shift)
    7277     * @return the rotated String,
    7278     *          or the original String if {@code shift == 0},
    7279     *          or {@code null} if null String input
    7280     * @since 3.5
    7281     */
    7282    public static String rotate(final String str, final int shift) {
    7283        if (str == null) {
    7284            return null;
    7285        }
    7286
    7287        final int strLen = str.length();
    7288        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
    7289            return str;
    7290        }
    7291
    7292        final StringBuilder builder = new StringBuilder(strLen);
    7293        final int offset = - (shift % strLen);
    7294        builder.append(substring(str, offset));
    7295        builder.append(substring(str, 0, offset));
    7296        return builder.toString();
    7297    }
    7298
    7299    /**
    7300     * Splits the provided text into an array, using whitespace as the
    7301     * separator.
    7302     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7303     *
    7304     * <p>The separator is not included in the returned String array.
    7305     * Adjacent separators are treated as one separator.
    7306     * For more control over the split use the StrTokenizer class.</p>
    7307     *
    7308     * <p>A {@code null} input String returns {@code null}.</p>
    7309     *
    7310     * <pre>
    7311     * StringUtils.split(null)       = null
    7312     * StringUtils.split("")         = []
    7313     * StringUtils.split("abc def")  = ["abc", "def"]
    7314     * StringUtils.split("abc  def") = ["abc", "def"]
    7315     * StringUtils.split(" abc ")    = ["abc"]
    7316     * </pre>
    7317     *
    7318     * @param str  the String to parse, may be null
    7319     * @return an array of parsed Strings, {@code null} if null String input
    7320     */
    7321    public static String[] split(final String str) {
    7322        return split(str, null, -1);
    7323    }
    7324
    7325    /**
    7326     * Splits the provided text into an array, separator specified.
    7327     * This is an alternative to using StringTokenizer.
    7328     *
    7329     * <p>The separator is not included in the returned String array.
    7330     * Adjacent separators are treated as one separator.
    7331     * For more control over the split use the StrTokenizer class.</p>
    7332     *
    7333     * <p>A {@code null} input String returns {@code null}.</p>
    7334     *
    7335     * <pre>
    7336     * StringUtils.split(null, *)         = null
    7337     * StringUtils.split("", *)           = []
    7338     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    7339     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    7340     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    7341     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    7342     * </pre>
    7343     *
    7344     * @param str  the String to parse, may be null
    7345     * @param separatorChar  the character used as the delimiter
    7346     * @return an array of parsed Strings, {@code null} if null String input
    7347     * @since 2.0
    7348     */
    7349    public static String[] split(final String str, final char separatorChar) {
    7350        return splitWorker(str, separatorChar, false);
    7351    }
    7352
    7353    /**
    7354     * Splits the provided text into an array, separators specified.
    7355     * This is an alternative to using StringTokenizer.
    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}.
    7362     * A {@code null} separatorChars splits on whitespace.</p>
    7363     *
    7364     * <pre>
    7365     * StringUtils.split(null, *)         = null
    7366     * StringUtils.split("", *)           = []
    7367     * StringUtils.split("abc def", null) = ["abc", "def"]
    7368     * StringUtils.split("abc def", " ")  = ["abc", "def"]
    7369     * StringUtils.split("abc  def", " ") = ["abc", "def"]
    7370     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    7371     * </pre>
    7372     *
    7373     * @param str  the String to parse, may be null
    7374     * @param separatorChars  the characters used as the delimiters,
    7375     *  {@code null} splits on whitespace
    7376     * @return an array of parsed Strings, {@code null} if null String input
    7377     */
    7378    public static String[] split(final String str, final String separatorChars) {
    7379        return splitWorker(str, separatorChars, -1, false);
    7380    }
    7381
    7382    /**
    7383     * Splits the provided text into an array with a maximum length,
    7384     * separators specified.
    7385     *
    7386     * <p>The separator is not included in the returned String array.
    7387     * Adjacent separators are treated as one separator.</p>
    7388     *
    7389     * <p>A {@code null} input String returns {@code null}.
    7390     * A {@code null} separatorChars splits on whitespace.</p>
    7391     *
    7392     * <p>If more than {@code max} delimited substrings are found, the last
    7393     * returned string includes all characters after the first {@code max - 1}
    7394     * returned strings (including separator characters).</p>
    7395     *
    7396     * <pre>
    7397     * StringUtils.split(null, *, *)            = null
    7398     * StringUtils.split("", *, *)              = []
    7399     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
    7400     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
    7401     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7402     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7403     * </pre>
    7404     *
    7405     * @param str  the String to parse, may be null
    7406     * @param separatorChars  the characters used as the delimiters,
    7407     *  {@code null} splits on whitespace
    7408     * @param max  the maximum number of elements to include in the
    7409     *  array. A zero or negative value implies no limit
    7410     * @return an array of parsed Strings, {@code null} if null String input
    7411     */
    7412    public static String[] split(final String str, final String separatorChars, final int max) {
    7413        return splitWorker(str, separatorChars, max, false);
    7414    }
    7415
    7416    /**
    7417     * Splits a String by Character type as returned by
    7418     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7419     * characters of the same type are returned as complete tokens.
    7420     * <pre>
    7421     * StringUtils.splitByCharacterType(null)         = null
    7422     * StringUtils.splitByCharacterType("")           = []
    7423     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7424     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7425     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7426     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    7427     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    7428     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    7429     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    7430     * </pre>
    7431     * @param str the String to split, may be {@code null}
    7432     * @return an array of parsed Strings, {@code null} if null String input
    7433     * @since 2.4
    7434     */
    7435    public static String[] splitByCharacterType(final String str) {
    7436        return splitByCharacterType(str, false);
    7437    }
    7438
    7439    /**
    7440     * <p>Splits a String by Character type as returned by
    7441     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7442     * characters of the same type are returned as complete tokens, with the
    7443     * following exception: if {@code camelCase} is {@code true},
    7444     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
    7445     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
    7446     * will belong to the following token rather than to the preceding, if any,
    7447     * {@code Character.UPPERCASE_LETTER} token.
    7448     * @param str the String to split, may be {@code null}
    7449     * @param camelCase whether to use so-called "camel-case" for letter types
    7450     * @return an array of parsed Strings, {@code null} if null String input
    7451     * @since 2.4
    7452     */
    7453    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
    7454        if (str == null) {
    7455            return null;
    7456        }
    7457        if (str.isEmpty()) {
    7458            return ArrayUtils.EMPTY_STRING_ARRAY;
    7459        }
    7460        final char[] c = str.toCharArray();
    7461        final List<String> list = new ArrayList<>();
    7462        int tokenStart = 0;
    7463        int currentType = Character.getType(c[tokenStart]);
    7464        for (int pos = tokenStart + 1; pos < c.length; pos++) {
    7465            final int type = Character.getType(c[pos]);
    7466            if (type == currentType) {
    7467                continue;
    7468            }
    7469            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    7470                final int newTokenStart = pos - 1;
    7471                if (newTokenStart != tokenStart) {
    7472                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    7473                    tokenStart = newTokenStart;
    7474                }
    7475            } else {
    7476                list.add(new String(c, tokenStart, pos - tokenStart));
    7477                tokenStart = pos;
    7478            }
    7479            currentType = type;
    7480        }
    7481        list.add(new String(c, tokenStart, c.length - tokenStart));
    7482        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7483    }
    7484
    7485    /**
    7486     * <p>Splits a String by Character type as returned by
    7487     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    7488     * characters of the same type are returned as complete tokens, with the
    7489     * following exception: the character of type
    7490     * {@code Character.UPPERCASE_LETTER}, if any, immediately
    7491     * preceding a token of type {@code Character.LOWERCASE_LETTER}
    7492     * will belong to the following token rather than to the preceding, if any,
    7493     * {@code Character.UPPERCASE_LETTER} token.
    7494     * <pre>
    7495     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    7496     * StringUtils.splitByCharacterTypeCamelCase("")           = []
    7497     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    7498     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    7499     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    7500     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    7501     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    7502     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    7503     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    7504     * </pre>
    7505     * @param str the String to split, may be {@code null}
    7506     * @return an array of parsed Strings, {@code null} if null String input
    7507     * @since 2.4
    7508     */
    7509    public static String[] splitByCharacterTypeCamelCase(final String str) {
    7510        return splitByCharacterType(str, true);
    7511    }
    7512
    7513    /**
    7514     * <p>Splits the provided text into an array, separator string specified.
    7515     *
    7516     * <p>The separator(s) will not be included in the returned String array.
    7517     * Adjacent separators are treated as one separator.</p>
    7518     *
    7519     * <p>A {@code null} input String returns {@code null}.
    7520     * A {@code null} separator splits on whitespace.</p>
    7521     *
    7522     * <pre>
    7523     * StringUtils.splitByWholeSeparator(null, *)               = null
    7524     * StringUtils.splitByWholeSeparator("", *)                 = []
    7525     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    7526     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    7527     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7528     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7529     * </pre>
    7530     *
    7531     * @param str  the String to parse, may be null
    7532     * @param separator  String containing the String to be used as a delimiter,
    7533     *  {@code null} splits on whitespace
    7534     * @return an array of parsed Strings, {@code null} if null String was input
    7535     */
    7536    public static String[] splitByWholeSeparator(final String str, final String separator) {
    7537        return splitByWholeSeparatorWorker(str, separator, -1, false);
    7538    }
    7539
    7540    /**
    7541     * Splits the provided text into an array, separator string specified.
    7542     * Returns a maximum of {@code max} substrings.
    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, 0)      = ["ab", "de", "fg"]
    7554     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    7555     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7556     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7557     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7558     * </pre>
    7559     *
    7560     * @param str  the String to parse, may be null
    7561     * @param separator  String containing the String to be used as a delimiter,
    7562     *  {@code null} splits on whitespace
    7563     * @param max  the maximum number of elements to include in the returned
    7564     *  array. A zero or negative value implies no limit.
    7565     * @return an array of parsed Strings, {@code null} if null String was input
    7566     */
    7567    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
    7568        return splitByWholeSeparatorWorker(str, separator, max, false);
    7569    }
    7570
    7571    /**
    7572     * Splits the provided text into an array, separator string specified.
    7573     *
    7574     * <p>The separator is not included in the returned String array.
    7575     * Adjacent separators are treated as separators for empty tokens.
    7576     * For more control over the split use the StrTokenizer class.</p>
    7577     *
    7578     * <p>A {@code null} input String returns {@code null}.
    7579     * A {@code null} separator splits on whitespace.</p>
    7580     *
    7581     * <pre>
    7582     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    7583     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    7584     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    7585     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    7586     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    7587     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    7588     * </pre>
    7589     *
    7590     * @param str  the String to parse, may be null
    7591     * @param separator  String containing the String to be used as a delimiter,
    7592     *  {@code null} splits on whitespace
    7593     * @return an array of parsed Strings, {@code null} if null String was input
    7594     * @since 2.4
    7595     */
    7596    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
    7597        return splitByWholeSeparatorWorker(str, separator, -1, true);
    7598    }
    7599
    7600    /**
    7601     * Splits the provided text into an array, separator string specified.
    7602     * Returns a maximum of {@code max} substrings.
    7603     *
    7604     * <p>The separator is not included in the returned String array.
    7605     * Adjacent separators are treated as separators for empty tokens.
    7606     * For more control over the split use the StrTokenizer class.</p>
    7607     *
    7608     * <p>A {@code null} input String returns {@code null}.
    7609     * A {@code null} separator splits on whitespace.</p>
    7610     *
    7611     * <pre>
    7612     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    7613     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    7614     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    7615     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    7616     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    7617     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    7618     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    7619     * </pre>
    7620     *
    7621     * @param str  the String to parse, may be null
    7622     * @param separator  String containing the String to be used as a delimiter,
    7623     *  {@code null} splits on whitespace
    7624     * @param max  the maximum number of elements to include in the returned
    7625     *  array. A zero or negative value implies no limit.
    7626     * @return an array of parsed Strings, {@code null} if null String was input
    7627     * @since 2.4
    7628     */
    7629    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
    7630        return splitByWholeSeparatorWorker(str, separator, max, true);
    7631    }
    7632
    7633    /**
    7634     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
    7635     *
    7636     * @param str  the String to parse, may be {@code null}
    7637     * @param separator  String containing the String to be used as a delimiter,
    7638     *  {@code null} splits on whitespace
    7639     * @param max  the maximum number of elements to include in the returned
    7640     *  array. A zero or negative value implies no limit.
    7641     * @param preserveAllTokens if {@code true}, adjacent separators are
    7642     * treated as empty token separators; if {@code false}, adjacent
    7643     * separators are treated as one separator.
    7644     * @return an array of parsed Strings, {@code null} if null String input
    7645     * @since 2.4
    7646     */
    7647    private static String[] splitByWholeSeparatorWorker(
    7648            final String str, final String separator, final int max, final boolean preserveAllTokens) {
    7649        if (str == null) {
    7650            return null;
    7651        }
    7652
    7653        final int len = str.length();
    7654
    7655        if (len == 0) {
    7656            return ArrayUtils.EMPTY_STRING_ARRAY;
    7657        }
    7658
    7659        if (separator == null || EMPTY.equals(separator)) {
    7660            // Split on whitespace.
    7661            return splitWorker(str, null, max, preserveAllTokens);
    7662        }
    7663
    7664        final int separatorLength = separator.length();
    7665
    7666        final ArrayList<String> substrings = new ArrayList<>();
    7667        int numberOfSubstrings = 0;
    7668        int beg = 0;
    7669        int end = 0;
    7670        while (end < len) {
    7671            end = str.indexOf(separator, beg);
    7672
    7673            if (end > -1) {
    7674                if (end > beg) {
    7675                    numberOfSubstrings += 1;
    7676
    7677                    if (numberOfSubstrings == max) {
    7678                        end = len;
    7679                        substrings.add(str.substring(beg));
    7680                    } else {
    7681                        // The following is OK, because String.substring( beg, end ) excludes
    7682                        // the character at the position 'end'.
    7683                        substrings.add(str.substring(beg, end));
    7684
    7685                        // Set the starting point for the next search.
    7686                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    7687                        // which is the right calculation:
    7688                        beg = end + separatorLength;
    7689                    }
    7690                } else {
    7691                    // We found a consecutive occurrence of the separator, so skip it.
    7692                    if (preserveAllTokens) {
    7693                        numberOfSubstrings += 1;
    7694                        if (numberOfSubstrings == max) {
    7695                            end = len;
    7696                            substrings.add(str.substring(beg));
    7697                        } else {
    7698                            substrings.add(EMPTY);
    7699                        }
    7700                    }
    7701                    beg = end + separatorLength;
    7702                }
    7703            } else {
    7704                // String.substring( beg ) goes from 'beg' to the end of the String.
    7705                substrings.add(str.substring(beg));
    7706                end = len;
    7707            }
    7708        }
    7709
    7710        return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7711    }
    7712
    7713    /**
    7714     * Splits the provided text into an array, using whitespace as the
    7715     * separator, preserving all tokens, including empty tokens created by
    7716     * adjacent separators. This is an alternative to using StringTokenizer.
    7717     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    7718     *
    7719     * <p>The separator is not included in the returned String array.
    7720     * Adjacent separators are treated as separators for empty tokens.
    7721     * For more control over the split use the StrTokenizer class.</p>
    7722     *
    7723     * <p>A {@code null} input String returns {@code null}.</p>
    7724     *
    7725     * <pre>
    7726     * StringUtils.splitPreserveAllTokens(null)       = null
    7727     * StringUtils.splitPreserveAllTokens("")         = []
    7728     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    7729     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    7730     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    7731     * </pre>
    7732     *
    7733     * @param str  the String to parse, may be {@code null}
    7734     * @return an array of parsed Strings, {@code null} if null String input
    7735     * @since 2.1
    7736     */
    7737    public static String[] splitPreserveAllTokens(final String str) {
    7738        return splitWorker(str, null, -1, true);
    7739    }
    7740
    7741    /**
    7742     * Splits the provided text into an array, separator specified,
    7743     * preserving all tokens, including empty tokens created by adjacent
    7744     * separators. This is an alternative to using StringTokenizer.
    7745     *
    7746     * <p>The separator is not included in the returned String array.
    7747     * Adjacent separators are treated as separators for empty tokens.
    7748     * For more control over the split use the StrTokenizer class.</p>
    7749     *
    7750     * <p>A {@code null} input String returns {@code null}.</p>
    7751     *
    7752     * <pre>
    7753     * StringUtils.splitPreserveAllTokens(null, *)         = null
    7754     * StringUtils.splitPreserveAllTokens("", *)           = []
    7755     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    7756     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    7757     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    7758     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    7759     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    7760     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    7761     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
    7762     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
    7763     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
    7764     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
    7765     * </pre>
    7766     *
    7767     * @param str  the String to parse, may be {@code null}
    7768     * @param separatorChar  the character used as the delimiter,
    7769     *  {@code null} splits on whitespace
    7770     * @return an array of parsed Strings, {@code null} if null String input
    7771     * @since 2.1
    7772     */
    7773    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
    7774        return splitWorker(str, separatorChar, true);
    7775    }
    7776
    7777    /**
    7778     * Splits the provided text into an array, separators specified,
    7779     * preserving all tokens, including empty tokens created by adjacent
    7780     * separators. This is an alternative to using StringTokenizer.
    7781     *
    7782     * <p>The separator is not included in the returned String array.
    7783     * Adjacent separators are treated as separators for empty tokens.
    7784     * For more control over the split use the StrTokenizer class.</p>
    7785     *
    7786     * <p>A {@code null} input String returns {@code null}.
    7787     * A {@code null} separatorChars splits on whitespace.</p>
    7788     *
    7789     * <pre>
    7790     * StringUtils.splitPreserveAllTokens(null, *)           = null
    7791     * StringUtils.splitPreserveAllTokens("", *)             = []
    7792     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    7793     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    7794     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
    7795     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    7796     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    7797     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    7798     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
    7799     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
    7800     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
    7801     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
    7802     * </pre>
    7803     *
    7804     * @param str  the String to parse, may be {@code null}
    7805     * @param separatorChars  the characters used as the delimiters,
    7806     *  {@code null} splits on whitespace
    7807     * @return an array of parsed Strings, {@code null} if null String input
    7808     * @since 2.1
    7809     */
    7810    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
    7811        return splitWorker(str, separatorChars, -1, true);
    7812    }
    7813
    7814    /**
    7815     * Splits the provided text into an array with a maximum length,
    7816     * separators specified, preserving all tokens, including empty tokens
    7817     * created by adjacent separators.
    7818     *
    7819     * <p>The separator is not included in the returned String array.
    7820     * Adjacent separators are treated as separators for empty tokens.
    7821     * Adjacent separators are treated as one separator.</p>
    7822     *
    7823     * <p>A {@code null} input String returns {@code null}.
    7824     * A {@code null} separatorChars splits on whitespace.</p>
    7825     *
    7826     * <p>If more than {@code max} delimited substrings are found, the last
    7827     * returned string includes all characters after the first {@code max - 1}
    7828     * returned strings (including separator characters).</p>
    7829     *
    7830     * <pre>
    7831     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    7832     * StringUtils.splitPreserveAllTokens("", *, *)              = []
    7833     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
    7834     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
    7835     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    7836     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    7837     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    7838     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    7839     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    7840     * </pre>
    7841     *
    7842     * @param str  the String to parse, may be {@code null}
    7843     * @param separatorChars  the characters used as the delimiters,
    7844     *  {@code null} splits on whitespace
    7845     * @param max  the maximum number of elements to include in the
    7846     *  array. A zero or negative value implies no limit
    7847     * @return an array of parsed Strings, {@code null} if null String input
    7848     * @since 2.1
    7849     */
    7850    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
    7851        return splitWorker(str, separatorChars, max, true);
    7852    }
    7853
    7854    /**
    7855     * Performs the logic for the {@code split} and
    7856     * {@code splitPreserveAllTokens} methods that do not return a
    7857     * maximum array length.
    7858     *
    7859     * @param str  the String to parse, may be {@code null}
    7860     * @param separatorChar the separate character
    7861     * @param preserveAllTokens if {@code true}, adjacent separators are
    7862     * treated as empty token separators; if {@code false}, adjacent
    7863     * separators are treated as one separator.
    7864     * @return an array of parsed Strings, {@code null} if null String input
    7865     */
    7866    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
    7867        // Performance tuned for 2.0 (JDK1.4)
    7868        if (str == null) {
    7869            return null;
    7870        }
    7871        final int len = str.length();
    7872        if (len == 0) {
    7873            return ArrayUtils.EMPTY_STRING_ARRAY;
    7874        }
    7875        final List<String> list = new ArrayList<>();
    7876        int i = 0;
    7877        int start = 0;
    7878        boolean match = false;
    7879        boolean lastMatch = false;
    7880        while (i < len) {
    7881            if (str.charAt(i) == separatorChar) {
    7882                if (match || preserveAllTokens) {
    7883                    list.add(str.substring(start, i));
    7884                    match = false;
    7885                    lastMatch = true;
    7886                }
    7887                start = ++i;
    7888                continue;
    7889            }
    7890            lastMatch = false;
    7891            match = true;
    7892            i++;
    7893        }
    7894        if (match || preserveAllTokens && lastMatch) {
    7895            list.add(str.substring(start, i));
    7896        }
    7897        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7898    }
    7899
    7900    /**
    7901     * Performs the logic for the {@code split} and
    7902     * {@code splitPreserveAllTokens} methods that return a maximum array
    7903     * length.
    7904     *
    7905     * @param str  the String to parse, may be {@code null}
    7906     * @param separatorChars the separate character
    7907     * @param max  the maximum number of elements to include in the
    7908     *  array. A zero or negative value implies no limit.
    7909     * @param preserveAllTokens if {@code true}, adjacent separators are
    7910     * treated as empty token separators; if {@code false}, adjacent
    7911     * separators are treated as one separator.
    7912     * @return an array of parsed Strings, {@code null} if null String input
    7913     */
    7914    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
    7915        // Performance tuned for 2.0 (JDK1.4)
    7916        // Direct code is quicker than StringTokenizer.
    7917        // Also, StringTokenizer uses isSpace() not isWhitespace()
    7918
    7919        if (str == null) {
    7920            return null;
    7921        }
    7922        final int len = str.length();
    7923        if (len == 0) {
    7924            return ArrayUtils.EMPTY_STRING_ARRAY;
    7925        }
    7926        final List<String> list = new ArrayList<>();
    7927        int sizePlus1 = 1;
    7928        int i = 0;
    7929        int start = 0;
    7930        boolean match = false;
    7931        boolean lastMatch = false;
    7932        if (separatorChars == null) {
    7933            // Null separator means use whitespace
    7934            while (i < len) {
    7935                if (Character.isWhitespace(str.charAt(i))) {
    7936                    if (match || preserveAllTokens) {
    7937                        lastMatch = true;
    7938                        if (sizePlus1++ == max) {
    7939                            i = len;
    7940                            lastMatch = false;
    7941                        }
    7942                        list.add(str.substring(start, i));
    7943                        match = false;
    7944                    }
    7945                    start = ++i;
    7946                    continue;
    7947                }
    7948                lastMatch = false;
    7949                match = true;
    7950                i++;
    7951            }
    7952        } else if (separatorChars.length() == 1) {
    7953            // Optimise 1 character case
    7954            final char sep = separatorChars.charAt(0);
    7955            while (i < len) {
    7956                if (str.charAt(i) == sep) {
    7957                    if (match || preserveAllTokens) {
    7958                        lastMatch = true;
    7959                        if (sizePlus1++ == max) {
    7960                            i = len;
    7961                            lastMatch = false;
    7962                        }
    7963                        list.add(str.substring(start, i));
    7964                        match = false;
    7965                    }
    7966                    start = ++i;
    7967                    continue;
    7968                }
    7969                lastMatch = false;
    7970                match = true;
    7971                i++;
    7972            }
    7973        } else {
    7974            // standard case
    7975            while (i < len) {
    7976                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    7977                    if (match || preserveAllTokens) {
    7978                        lastMatch = true;
    7979                        if (sizePlus1++ == max) {
    7980                            i = len;
    7981                            lastMatch = false;
    7982                        }
    7983                        list.add(str.substring(start, i));
    7984                        match = false;
    7985                    }
    7986                    start = ++i;
    7987                    continue;
    7988                }
    7989                lastMatch = false;
    7990                match = true;
    7991                i++;
    7992            }
    7993        }
    7994        if (match || preserveAllTokens && lastMatch) {
    7995            list.add(str.substring(start, i));
    7996        }
    7997        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    7998    }
    7999
    8000    /**
    8001     * Check if a CharSequence starts with a specified prefix.
    8002     *
    8003     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8004     * references are considered to be equal. The comparison is case-sensitive.</p>
    8005     *
    8006     * <pre>
    8007     * StringUtils.startsWith(null, null)      = true
    8008     * StringUtils.startsWith(null, "abc")     = false
    8009     * StringUtils.startsWith("abcdef", null)  = false
    8010     * StringUtils.startsWith("abcdef", "abc") = true
    8011     * StringUtils.startsWith("ABCDEF", "abc") = false
    8012     * </pre>
    8013     *
    8014     * @see String#startsWith(String)
    8015     * @param str  the CharSequence to check, may be null
    8016     * @param prefix the prefix to find, may be null
    8017     * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
    8018     *  both {@code null}
    8019     * @since 2.4
    8020     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
    8021     */
    8022    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
    8023        return startsWith(str, prefix, false);
    8024    }
    8025
    8026    /**
    8027     * Check if a CharSequence starts with a specified prefix (optionally case insensitive).
    8028     *
    8029     * @see String#startsWith(String)
    8030     * @param str  the CharSequence to check, may be null
    8031     * @param prefix the prefix to find, may be null
    8032     * @param ignoreCase indicates whether the compare should ignore case
    8033     *  (case-insensitive) or not.
    8034     * @return {@code true} if the CharSequence starts with the prefix or
    8035     *  both {@code null}
    8036     */
    8037    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
    8038        if (str == null || prefix == null) {
    8039            return str == prefix;
    8040        }
    8041        // Get length once instead of twice in the unlikely case that it changes.
    8042        final int preLen = prefix.length();
    8043        if (preLen > str.length()) {
    8044            return false;
    8045        }
    8046        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen);
    8047    }
    8048
    8049    /**
    8050     * Check if a CharSequence starts with any of the provided case-sensitive prefixes.
    8051     *
    8052     * <pre>
    8053     * StringUtils.startsWithAny(null, null)      = false
    8054     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    8055     * StringUtils.startsWithAny("abcxyz", null)     = false
    8056     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
    8057     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    8058     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    8059     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
    8060     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
    8061     * </pre>
    8062     *
    8063     * @param sequence the CharSequence to check, may be null
    8064     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
    8065     * @see StringUtils#startsWith(CharSequence, CharSequence)
    8066     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    8067     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
    8068     * @since 2.5
    8069     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
    8070     */
    8071    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    8072        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    8073            return false;
    8074        }
    8075        for (final CharSequence searchString : searchStrings) {
    8076            if (startsWith(sequence, searchString)) {
    8077                return true;
    8078            }
    8079        }
    8080        return false;
    8081    }
    8082
    8083    /**
    8084     * Case insensitive check if a CharSequence starts with a specified prefix.
    8085     *
    8086     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8087     * references are considered to be equal. The comparison is case insensitive.</p>
    8088     *
    8089     * <pre>
    8090     * StringUtils.startsWithIgnoreCase(null, null)      = true
    8091     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    8092     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    8093     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    8094     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    8095     * </pre>
    8096     *
    8097     * @see String#startsWith(String)
    8098     * @param str  the CharSequence to check, may be null
    8099     * @param prefix the prefix to find, may be null
    8100     * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
    8101     *  both {@code null}
    8102     * @since 2.4
    8103     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
    8104     */
    8105    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
    8106        return startsWith(str, prefix, true);
    8107    }
    8108
    8109    /**
    8110     * Strips whitespace from the start and end of a String.
    8111     *
    8112     * <p>This is similar to {@link #trim(String)} but removes whitespace.
    8113     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8114     *
    8115     * <p>A {@code null} input String returns {@code null}.</p>
    8116     *
    8117     * <pre>
    8118     * StringUtils.strip(null)     = null
    8119     * StringUtils.strip("")       = ""
    8120     * StringUtils.strip("   ")    = ""
    8121     * StringUtils.strip("abc")    = "abc"
    8122     * StringUtils.strip("  abc")  = "abc"
    8123     * StringUtils.strip("abc  ")  = "abc"
    8124     * StringUtils.strip(" abc ")  = "abc"
    8125     * StringUtils.strip(" ab c ") = "ab c"
    8126     * </pre>
    8127     *
    8128     * @param str  the String to remove whitespace from, may be null
    8129     * @return the stripped String, {@code null} if null String input
    8130     */
    8131    public static String strip(final String str) {
    8132        return strip(str, null);
    8133    }
    8134
    8135    /**
    8136     * Strips any of a set of characters from the start and end of a String.
    8137     * This is similar to {@link String#trim()} but allows the characters
    8138     * to be stripped to be controlled.
    8139     *
    8140     * <p>A {@code null} input String returns {@code null}.
    8141     * An empty string ("") input returns the empty string.</p>
    8142     *
    8143     * <p>If the stripChars String is {@code null}, whitespace is
    8144     * stripped as defined by {@link Character#isWhitespace(char)}.
    8145     * Alternatively use {@link #strip(String)}.</p>
    8146     *
    8147     * <pre>
    8148     * StringUtils.strip(null, *)          = null
    8149     * StringUtils.strip("", *)            = ""
    8150     * StringUtils.strip("abc", null)      = "abc"
    8151     * StringUtils.strip("  abc", null)    = "abc"
    8152     * StringUtils.strip("abc  ", null)    = "abc"
    8153     * StringUtils.strip(" abc ", null)    = "abc"
    8154     * StringUtils.strip("  abcyx", "xyz") = "  abc"
    8155     * </pre>
    8156     *
    8157     * @param str  the String to remove characters from, may be null
    8158     * @param stripChars  the characters to remove, null treated as whitespace
    8159     * @return the stripped String, {@code null} if null String input
    8160     */
    8161    public static String strip(String str, final String stripChars) {
    8162        str = stripStart(str, stripChars);
    8163        return stripEnd(str, stripChars);
    8164    }
    8165
    8166    /**
    8167     * Removes diacritics (~= accents) from a string. The case will not be altered.
    8168     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
    8169     * <p>Decomposes ligatures and digraphs per the KD column in the
    8170     * <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a></p>
    8171     *
    8172     * <pre>
    8173     * StringUtils.stripAccents(null)                = null
    8174     * StringUtils.stripAccents("")                  = ""
    8175     * StringUtils.stripAccents("control")           = "control"
    8176     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
    8177     * </pre>
    8178     *
    8179     * @param input String to be stripped
    8180     * @return input text with diacritics removed
    8181     *
    8182     * @since 3.0
    8183     */
    8184    // 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).
    8185    public static String stripAccents(final String input) {
    8186        if (isEmpty(input)) {
    8187            return input;
    8188        }
    8189        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
    8190        convertRemainingAccentCharacters(decomposed);
    8191        return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
    8192    }
    8193
    8194    /**
    8195     * Strips whitespace from the start and end of every String in an array.
    8196     * Whitespace is defined by {@link Character#isWhitespace(char)}.
    8197     *
    8198     * <p>A new array is returned each time, except for length zero.
    8199     * A {@code null} array will return {@code null}.
    8200     * An empty array will return itself.
    8201     * A {@code null} array entry will be ignored.</p>
    8202     *
    8203     * <pre>
    8204     * StringUtils.stripAll(null)             = null
    8205     * StringUtils.stripAll([])               = []
    8206     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    8207     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    8208     * </pre>
    8209     *
    8210     * @param strs  the array to remove whitespace from, may be null
    8211     * @return the stripped Strings, {@code null} if null array input
    8212     */
    8213    public static String[] stripAll(final String... strs) {
    8214        return stripAll(strs, null);
    8215    }
    8216
    8217    /**
    8218     * Strips any of a set of characters from the start and end of every
    8219     * String in an array.
    8220     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8221     *
    8222     * <p>A new array is returned each time, except for length zero.
    8223     * A {@code null} array will return {@code null}.
    8224     * An empty array will return itself.
    8225     * A {@code null} array entry will be ignored.
    8226     * A {@code null} stripChars will strip whitespace as defined by
    8227     * {@link Character#isWhitespace(char)}.</p>
    8228     *
    8229     * <pre>
    8230     * StringUtils.stripAll(null, *)                = null
    8231     * StringUtils.stripAll([], *)                  = []
    8232     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    8233     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    8234     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    8235     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    8236     * </pre>
    8237     *
    8238     * @param strs  the array to remove characters from, may be null
    8239     * @param stripChars  the characters to remove, null treated as whitespace
    8240     * @return the stripped Strings, {@code null} if null array input
    8241     */
    8242    public static String[] stripAll(final String[] strs, final String stripChars) {
    8243        final int strsLen = ArrayUtils.getLength(strs);
    8244        if (strsLen == 0) {
    8245            return strs;
    8246        }
    8247        final String[] newArr = new String[strsLen];
    8248        Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
    8249        return newArr;
    8250    }
    8251
    8252    /**
    8253     * Strips any of a set of characters from the end of a String.
    8254     *
    8255     * <p>A {@code null} input String returns {@code null}.
    8256     * An empty string ("") input returns the empty string.</p>
    8257     *
    8258     * <p>If the stripChars String is {@code null}, whitespace is
    8259     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8260     *
    8261     * <pre>
    8262     * StringUtils.stripEnd(null, *)          = null
    8263     * StringUtils.stripEnd("", *)            = ""
    8264     * StringUtils.stripEnd("abc", "")        = "abc"
    8265     * StringUtils.stripEnd("abc", null)      = "abc"
    8266     * StringUtils.stripEnd("  abc", null)    = "  abc"
    8267     * StringUtils.stripEnd("abc  ", null)    = "abc"
    8268     * StringUtils.stripEnd(" abc ", null)    = " abc"
    8269     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    8270     * StringUtils.stripEnd("120.00", ".0")   = "12"
    8271     * </pre>
    8272     *
    8273     * @param str  the String to remove characters from, may be null
    8274     * @param stripChars  the set of characters to remove, null treated as whitespace
    8275     * @return the stripped String, {@code null} if null String input
    8276     */
    8277    public static String stripEnd(final String str, final String stripChars) {
    8278        int end = length(str);
    8279        if (end == 0) {
    8280            return str;
    8281        }
    8282
    8283        if (stripChars == null) {
    8284            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
    8285                end--;
    8286            }
    8287        } else if (stripChars.isEmpty()) {
    8288            return str;
    8289        } else {
    8290            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
    8291                end--;
    8292            }
    8293        }
    8294        return str.substring(0, end);
    8295    }
    8296
    8297    /**
    8298     * Strips any of a set of characters from the start of a String.
    8299     *
    8300     * <p>A {@code null} input String returns {@code null}.
    8301     * An empty string ("") input returns the empty string.</p>
    8302     *
    8303     * <p>If the stripChars String is {@code null}, whitespace is
    8304     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    8305     *
    8306     * <pre>
    8307     * StringUtils.stripStart(null, *)          = null
    8308     * StringUtils.stripStart("", *)            = ""
    8309     * StringUtils.stripStart("abc", "")        = "abc"
    8310     * StringUtils.stripStart("abc", null)      = "abc"
    8311     * StringUtils.stripStart("  abc", null)    = "abc"
    8312     * StringUtils.stripStart("abc  ", null)    = "abc  "
    8313     * StringUtils.stripStart(" abc ", null)    = "abc "
    8314     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    8315     * </pre>
    8316     *
    8317     * @param str  the String to remove characters from, may be null
    8318     * @param stripChars  the characters to remove, null treated as whitespace
    8319     * @return the stripped String, {@code null} if null String input
    8320     */
    8321    public static String stripStart(final String str, final String stripChars) {
    8322        final int strLen = length(str);
    8323        if (strLen == 0) {
    8324            return str;
    8325        }
    8326        int start = 0;
    8327        if (stripChars == null) {
    8328            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
    8329                start++;
    8330            }
    8331        } else if (stripChars.isEmpty()) {
    8332            return str;
    8333        } else {
    8334            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
    8335                start++;
    8336            }
    8337        }
    8338        return str.substring(start);
    8339    }
    8340
    8341    /**
    8342     * Strips whitespace from the start and end of a String  returning
    8343     * an empty String if {@code null} input.
    8344     *
    8345     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
    8346     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8347     *
    8348     * <pre>
    8349     * StringUtils.stripToEmpty(null)     = ""
    8350     * StringUtils.stripToEmpty("")       = ""
    8351     * StringUtils.stripToEmpty("   ")    = ""
    8352     * StringUtils.stripToEmpty("abc")    = "abc"
    8353     * StringUtils.stripToEmpty("  abc")  = "abc"
    8354     * StringUtils.stripToEmpty("abc  ")  = "abc"
    8355     * StringUtils.stripToEmpty(" abc ")  = "abc"
    8356     * StringUtils.stripToEmpty(" ab c ") = "ab c"
    8357     * </pre>
    8358     *
    8359     * @param str  the String to be stripped, may be null
    8360     * @return the trimmed String, or an empty String if {@code null} input
    8361     * @since 2.0
    8362     */
    8363    public static String stripToEmpty(final String str) {
    8364        return str == null ? EMPTY : strip(str, null);
    8365    }
    8366
    8367    /**
    8368     * Strips whitespace from the start and end of a String  returning
    8369     * {@code null} if the String is empty ("") after the strip.
    8370     *
    8371     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
    8372     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    8373     *
    8374     * <pre>
    8375     * StringUtils.stripToNull(null)     = null
    8376     * StringUtils.stripToNull("")       = null
    8377     * StringUtils.stripToNull("   ")    = null
    8378     * StringUtils.stripToNull("abc")    = "abc"
    8379     * StringUtils.stripToNull("  abc")  = "abc"
    8380     * StringUtils.stripToNull("abc  ")  = "abc"
    8381     * StringUtils.stripToNull(" abc ")  = "abc"
    8382     * StringUtils.stripToNull(" ab c ") = "ab c"
    8383     * </pre>
    8384     *
    8385     * @param str  the String to be stripped, may be null
    8386     * @return the stripped String,
    8387     *  {@code null} if whitespace, empty or null String input
    8388     * @since 2.0
    8389     */
    8390    public static String stripToNull(String str) {
    8391        if (str == null) {
    8392            return null;
    8393        }
    8394        str = strip(str, null);
    8395        return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
    8396    }
    8397
    8398    /**
    8399     * Gets a substring from the specified String avoiding exceptions.
    8400     *
    8401     * <p>A negative start position can be used to start {@code n}
    8402     * characters from the end of the String.</p>
    8403     *
    8404     * <p>A {@code null} String will return {@code null}.
    8405     * An empty ("") String will return "".</p>
    8406     *
    8407     * <pre>
    8408     * StringUtils.substring(null, *)   = null
    8409     * StringUtils.substring("", *)     = ""
    8410     * StringUtils.substring("abc", 0)  = "abc"
    8411     * StringUtils.substring("abc", 2)  = "c"
    8412     * StringUtils.substring("abc", 4)  = ""
    8413     * StringUtils.substring("abc", -2) = "bc"
    8414     * StringUtils.substring("abc", -4) = "abc"
    8415     * </pre>
    8416     *
    8417     * @param str  the String to get the substring from, may be null
    8418     * @param start  the position to start from, negative means
    8419     *  count back from the end of the String by this many characters
    8420     * @return substring from start position, {@code null} if null String input
    8421     */
    8422    public static String substring(final String str, int start) {
    8423        if (str == null) {
    8424            return null;
    8425        }
    8426
    8427        // handle negatives, which means last n characters
    8428        if (start < 0) {
    8429            start = str.length() + start; // remember start is negative
    8430        }
    8431
    8432        if (start < 0) {
    8433            start = 0;
    8434        }
    8435        if (start > str.length()) {
    8436            return EMPTY;
    8437        }
    8438
    8439        return str.substring(start);
    8440    }
    8441
    8442    /**
    8443     * Gets a substring from the specified String avoiding exceptions.
    8444     *
    8445     * <p>A negative start position can be used to start/end {@code n}
    8446     * characters from the end of the String.</p>
    8447     *
    8448     * <p>The returned substring starts with the character in the {@code start}
    8449     * position and ends before the {@code end} position. All position counting is
    8450     * zero-based -- i.e., to start at the beginning of the string use
    8451     * {@code start = 0}. Negative start and end positions can be used to
    8452     * specify offsets relative to the end of the String.</p>
    8453     *
    8454     * <p>If {@code start} is not strictly to the left of {@code end}, ""
    8455     * is returned.</p>
    8456     *
    8457     * <pre>
    8458     * StringUtils.substring(null, *, *)    = null
    8459     * StringUtils.substring("", * ,  *)    = "";
    8460     * StringUtils.substring("abc", 0, 2)   = "ab"
    8461     * StringUtils.substring("abc", 2, 0)   = ""
    8462     * StringUtils.substring("abc", 2, 4)   = "c"
    8463     * StringUtils.substring("abc", 4, 6)   = ""
    8464     * StringUtils.substring("abc", 2, 2)   = ""
    8465     * StringUtils.substring("abc", -2, -1) = "b"
    8466     * StringUtils.substring("abc", -4, 2)  = "ab"
    8467     * </pre>
    8468     *
    8469     * @param str  the String to get the substring from, may be null
    8470     * @param start  the position to start from, negative means
    8471     *  count back from the end of the String by this many characters
    8472     * @param end  the position to end at (exclusive), negative means
    8473     *  count back from the end of the String by this many characters
    8474     * @return substring from start position to end position,
    8475     *  {@code null} if null String input
    8476     */
    8477    public static String substring(final String str, int start, int end) {
    8478        if (str == null) {
    8479            return null;
    8480        }
    8481
    8482        // handle negatives
    8483        if (end < 0) {
    8484            end = str.length() + end; // remember end is negative
    8485        }
    8486        if (start < 0) {
    8487            start = str.length() + start; // remember start is negative
    8488        }
    8489
    8490        // check length next
    8491        if (end > str.length()) {
    8492            end = str.length();
    8493        }
    8494
    8495        // if start is greater than end, return ""
    8496        if (start > end) {
    8497            return EMPTY;
    8498        }
    8499
    8500        if (start < 0) {
    8501            start = 0;
    8502        }
    8503        if (end < 0) {
    8504            end = 0;
    8505        }
    8506
    8507        return str.substring(start, end);
    8508    }
    8509
    8510    /**
    8511     * Gets the substring after the first occurrence of a separator.
    8512     * The separator is not returned.
    8513     *
    8514     * <p>A {@code null} string input will return {@code null}.
    8515     * An empty ("") string input will return the empty string.
    8516     *
    8517     * <p>If nothing is found, the empty string is returned.</p>
    8518     *
    8519     * <pre>
    8520     * StringUtils.substringAfter(null, *)      = null
    8521     * StringUtils.substringAfter("", *)        = ""
    8522     * StringUtils.substringAfter("abc", 'a')   = "bc"
    8523     * StringUtils.substringAfter("abcba", 'b') = "cba"
    8524     * StringUtils.substringAfter("abc", 'c')   = ""
    8525     * StringUtils.substringAfter("abc", 'd')   = ""
    8526     * StringUtils.substringAfter(" abc", 32)   = "abc"
    8527     * </pre>
    8528     *
    8529     * @param str  the String to get a substring from, may be null
    8530     * @param separator  the character (Unicode code point) to search.
    8531     * @return the substring after the first occurrence of the separator,
    8532     *  {@code null} if null String input
    8533     * @since 3.11
    8534     */
    8535    public static String substringAfter(final String str, final int separator) {
    8536        if (isEmpty(str)) {
    8537            return str;
    8538        }
    8539        final int pos = str.indexOf(separator);
    8540        if (pos == INDEX_NOT_FOUND) {
    8541            return EMPTY;
    8542        }
    8543        return str.substring(pos + 1);
    8544    }
    8545
    8546    /**
    8547     * Gets the substring after the first occurrence of a separator.
    8548     * The separator is not returned.
    8549     *
    8550     * <p>A {@code null} string input will return {@code null}.
    8551     * An empty ("") string input will return the empty string.
    8552     * A {@code null} separator will return the empty string if the
    8553     * input string is not {@code null}.</p>
    8554     *
    8555     * <p>If nothing is found, the empty string is returned.</p>
    8556     *
    8557     * <pre>
    8558     * StringUtils.substringAfter(null, *)      = null
    8559     * StringUtils.substringAfter("", *)        = ""
    8560     * StringUtils.substringAfter(*, null)      = ""
    8561     * StringUtils.substringAfter("abc", "a")   = "bc"
    8562     * StringUtils.substringAfter("abcba", "b") = "cba"
    8563     * StringUtils.substringAfter("abc", "c")   = ""
    8564     * StringUtils.substringAfter("abc", "d")   = ""
    8565     * StringUtils.substringAfter("abc", "")    = "abc"
    8566     * </pre>
    8567     *
    8568     * @param str  the String to get a substring from, may be null
    8569     * @param separator  the String to search for, may be null
    8570     * @return the substring after the first occurrence of the separator,
    8571     *  {@code null} if null String input
    8572     * @since 2.0
    8573     */
    8574    public static String substringAfter(final String str, final String separator) {
    8575        if (isEmpty(str)) {
    8576            return str;
    8577        }
    8578        if (separator == null) {
    8579            return EMPTY;
    8580        }
    8581        final int pos = str.indexOf(separator);
    8582        if (pos == INDEX_NOT_FOUND) {
    8583            return EMPTY;
    8584        }
    8585        return str.substring(pos + separator.length());
    8586    }
    8587
    8588    /**
    8589     * Gets the substring after the last occurrence of a separator.
    8590     * The separator is not returned.
    8591     *
    8592     * <p>A {@code null} string input will return {@code null}.
    8593     * An empty ("") string input will return the empty string.
    8594     *
    8595     * <p>If nothing is found, the empty string is returned.</p>
    8596     *
    8597     * <pre>
    8598     * StringUtils.substringAfterLast(null, *)      = null
    8599     * StringUtils.substringAfterLast("", *)        = ""
    8600     * StringUtils.substringAfterLast("abc", 'a')   = "bc"
    8601     * StringUtils.substringAfterLast(" bc", 32)    = "bc"
    8602     * StringUtils.substringAfterLast("abcba", 'b') = "a"
    8603     * StringUtils.substringAfterLast("abc", 'c')   = ""
    8604     * StringUtils.substringAfterLast("a", 'a')     = ""
    8605     * StringUtils.substringAfterLast("a", 'z')     = ""
    8606     * </pre>
    8607     *
    8608     * @param str  the String to get a substring from, may be null
    8609     * @param separator  the character (Unicode code point) to search.
    8610     * @return the substring after the last occurrence of the separator,
    8611     *  {@code null} if null String input
    8612     * @since 3.11
    8613     */
    8614    public static String substringAfterLast(final String str, final int separator) {
    8615        if (isEmpty(str)) {
    8616            return str;
    8617        }
    8618        final int pos = str.lastIndexOf(separator);
    8619        if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
    8620            return EMPTY;
    8621        }
    8622        return str.substring(pos + 1);
    8623    }
    8624
    8625    /**
    8626     * Gets the substring after the last occurrence of a separator.
    8627     * The separator is not returned.
    8628     *
    8629     * <p>A {@code null} string input will return {@code null}.
    8630     * An empty ("") string input will return the empty string.
    8631     * An empty or {@code null} separator will return the empty string if
    8632     * the input string is not {@code null}.</p>
    8633     *
    8634     * <p>If nothing is found, the empty string is returned.</p>
    8635     *
    8636     * <pre>
    8637     * StringUtils.substringAfterLast(null, *)      = null
    8638     * StringUtils.substringAfterLast("", *)        = ""
    8639     * StringUtils.substringAfterLast(*, "")        = ""
    8640     * StringUtils.substringAfterLast(*, null)      = ""
    8641     * StringUtils.substringAfterLast("abc", "a")   = "bc"
    8642     * StringUtils.substringAfterLast("abcba", "b") = "a"
    8643     * StringUtils.substringAfterLast("abc", "c")   = ""
    8644     * StringUtils.substringAfterLast("a", "a")     = ""
    8645     * StringUtils.substringAfterLast("a", "z")     = ""
    8646     * </pre>
    8647     *
    8648     * @param str  the String to get a substring from, may be null
    8649     * @param separator  the String to search for, may be null
    8650     * @return the substring after the last occurrence of the separator,
    8651     *  {@code null} if null String input
    8652     * @since 2.0
    8653     */
    8654    public static String substringAfterLast(final String str, final String separator) {
    8655        if (isEmpty(str)) {
    8656            return str;
    8657        }
    8658        if (isEmpty(separator)) {
    8659            return EMPTY;
    8660        }
    8661        final int pos = str.lastIndexOf(separator);
    8662        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
    8663            return EMPTY;
    8664        }
    8665        return str.substring(pos + separator.length());
    8666    }
    8667
    8668    /**
    8669     * Gets the substring before the first occurrence of a separator. The separator is not returned.
    8670     *
    8671     * <p>
    8672     * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
    8673     * </p>
    8674     *
    8675     * <p>
    8676     * If nothing is found, the string input is returned.
    8677     * </p>
    8678     *
    8679     * <pre>
    8680     * StringUtils.substringBefore(null, *)      = null
    8681     * StringUtils.substringBefore("", *)        = ""
    8682     * StringUtils.substringBefore("abc", 'a')   = ""
    8683     * StringUtils.substringBefore("abcba", 'b') = "a"
    8684     * StringUtils.substringBefore("abc", 'c')   = "ab"
    8685     * StringUtils.substringBefore("abc", 'd')   = "abc"
    8686     * </pre>
    8687     *
    8688     * @param str the String to get a substring from, may be null
    8689     * @param separator the character (Unicode code point) to search.
    8690     * @return the substring before the first occurrence of the separator, {@code null} if null String input
    8691     * @since 3.12.0
    8692     */
    8693    public static String substringBefore(final String str, final int separator) {
    8694        if (isEmpty(str)) {
    8695            return str;
    8696        }
    8697        final int pos = str.indexOf(separator);
    8698        if (pos == INDEX_NOT_FOUND) {
    8699            return str;
    8700        }
    8701        return str.substring(0, pos);
    8702    }
    8703
    8704    /**
    8705     * Gets the substring before the first occurrence of a separator.
    8706     * The separator is not returned.
    8707     *
    8708     * <p>A {@code null} string input will return {@code null}.
    8709     * An empty ("") string input will return the empty string.
    8710     * A {@code null} separator will return the input string.</p>
    8711     *
    8712     * <p>If nothing is found, the string input is returned.</p>
    8713     *
    8714     * <pre>
    8715     * StringUtils.substringBefore(null, *)      = null
    8716     * StringUtils.substringBefore("", *)        = ""
    8717     * StringUtils.substringBefore("abc", "a")   = ""
    8718     * StringUtils.substringBefore("abcba", "b") = "a"
    8719     * StringUtils.substringBefore("abc", "c")   = "ab"
    8720     * StringUtils.substringBefore("abc", "d")   = "abc"
    8721     * StringUtils.substringBefore("abc", "")    = ""
    8722     * StringUtils.substringBefore("abc", null)  = "abc"
    8723     * </pre>
    8724     *
    8725     * @param str  the String to get a substring from, may be null
    8726     * @param separator  the String to search for, may be null
    8727     * @return the substring before the first occurrence of the separator,
    8728     *  {@code null} if null String input
    8729     * @since 2.0
    8730     */
    8731    public static String substringBefore(final String str, final String separator) {
    8732        if (isEmpty(str) || separator == null) {
    8733            return str;
    8734        }
    8735        if (separator.isEmpty()) {
    8736            return EMPTY;
    8737        }
    8738        final int pos = str.indexOf(separator);
    8739        if (pos == INDEX_NOT_FOUND) {
    8740            return str;
    8741        }
    8742        return str.substring(0, pos);
    8743    }
    8744
    8745    /**
    8746     * Gets the substring before the last occurrence of a separator.
    8747     * The separator is not returned.
    8748     *
    8749     * <p>A {@code null} string input will return {@code null}.
    8750     * An empty ("") string input will return the empty string.
    8751     * An empty or {@code null} separator will return the input string.</p>
    8752     *
    8753     * <p>If nothing is found, the string input is returned.</p>
    8754     *
    8755     * <pre>
    8756     * StringUtils.substringBeforeLast(null, *)      = null
    8757     * StringUtils.substringBeforeLast("", *)        = ""
    8758     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    8759     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    8760     * StringUtils.substringBeforeLast("a", "a")     = ""
    8761     * StringUtils.substringBeforeLast("a", "z")     = "a"
    8762     * StringUtils.substringBeforeLast("a", null)    = "a"
    8763     * StringUtils.substringBeforeLast("a", "")      = "a"
    8764     * </pre>
    8765     *
    8766     * @param str  the String to get a substring from, may be null
    8767     * @param separator  the String to search for, may be null
    8768     * @return the substring before the last occurrence of the separator,
    8769     *  {@code null} if null String input
    8770     * @since 2.0
    8771     */
    8772    public static String substringBeforeLast(final String str, final String separator) {
    8773        if (isEmpty(str) || isEmpty(separator)) {
    8774            return str;
    8775        }
    8776        final int pos = str.lastIndexOf(separator);
    8777        if (pos == INDEX_NOT_FOUND) {
    8778            return str;
    8779        }
    8780        return str.substring(0, pos);
    8781    }
    8782
    8783    /**
    8784     * Gets the String that is nested in between two instances of the
    8785     * same String.
    8786     *
    8787     * <p>A {@code null} input String returns {@code null}.
    8788     * A {@code null} tag returns {@code null}.</p>
    8789     *
    8790     * <pre>
    8791     * StringUtils.substringBetween(null, *)            = null
    8792     * StringUtils.substringBetween("", "")             = ""
    8793     * StringUtils.substringBetween("", "tag")          = null
    8794     * StringUtils.substringBetween("tagabctag", null)  = null
    8795     * StringUtils.substringBetween("tagabctag", "")    = ""
    8796     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    8797     * </pre>
    8798     *
    8799     * @param str  the String containing the substring, may be null
    8800     * @param tag  the String before and after the substring, may be null
    8801     * @return the substring, {@code null} if no match
    8802     * @since 2.0
    8803     */
    8804    public static String substringBetween(final String str, final String tag) {
    8805        return substringBetween(str, tag, tag);
    8806    }
    8807
    8808    /**
    8809     * Gets the String that is nested in between two Strings.
    8810     * Only the first match is returned.
    8811     *
    8812     * <p>A {@code null} input String returns {@code null}.
    8813     * A {@code null} open/close returns {@code null} (no match).
    8814     * An empty ("") open and close returns an empty string.</p>
    8815     *
    8816     * <pre>
    8817     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    8818     * StringUtils.substringBetween(null, *, *)          = null
    8819     * StringUtils.substringBetween(*, null, *)          = null
    8820     * StringUtils.substringBetween(*, *, null)          = null
    8821     * StringUtils.substringBetween("", "", "")          = ""
    8822     * StringUtils.substringBetween("", "", "]")         = null
    8823     * StringUtils.substringBetween("", "[", "]")        = null
    8824     * StringUtils.substringBetween("yabcz", "", "")     = ""
    8825     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    8826     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    8827     * </pre>
    8828     *
    8829     * @param str  the String containing the substring, may be null
    8830     * @param open  the String before the substring, may be null
    8831     * @param close  the String after the substring, may be null
    8832     * @return the substring, {@code null} if no match
    8833     * @since 2.0
    8834     */
    8835    public static String substringBetween(final String str, final String open, final String close) {
    8836        if (!ObjectUtils.allNotNull(str, open, close)) {
    8837            return null;
    8838        }
    8839        final int start = str.indexOf(open);
    8840        if (start != INDEX_NOT_FOUND) {
    8841            final int end = str.indexOf(close, start + open.length());
    8842            if (end != INDEX_NOT_FOUND) {
    8843                return str.substring(start + open.length(), end);
    8844            }
    8845        }
    8846        return null;
    8847    }
    8848
    8849    /**
    8850     * Searches a String for substrings delimited by a start and end tag,
    8851     * returning all matching substrings in an array.
    8852     *
    8853     * <p>A {@code null} input String returns {@code null}.
    8854     * A {@code null} open/close returns {@code null} (no match).
    8855     * An empty ("") open/close returns {@code null} (no match).</p>
    8856     *
    8857     * <pre>
    8858     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    8859     * StringUtils.substringsBetween(null, *, *)            = null
    8860     * StringUtils.substringsBetween(*, null, *)            = null
    8861     * StringUtils.substringsBetween(*, *, null)            = null
    8862     * StringUtils.substringsBetween("", "[", "]")          = []
    8863     * </pre>
    8864     *
    8865     * @param str  the String containing the substrings, null returns null, empty returns empty
    8866     * @param open  the String identifying the start of the substring, empty returns null
    8867     * @param close  the String identifying the end of the substring, empty returns null
    8868     * @return a String Array of substrings, or {@code null} if no match
    8869     * @since 2.3
    8870     */
    8871    public static String[] substringsBetween(final String str, final String open, final String close) {
    8872        if (str == null || isEmpty(open) || isEmpty(close)) {
    8873            return null;
    8874        }
    8875        final int strLen = str.length();
    8876        if (strLen == 0) {
    8877            return ArrayUtils.EMPTY_STRING_ARRAY;
    8878        }
    8879        final int closeLen = close.length();
    8880        final int openLen = open.length();
    8881        final List<String> list = new ArrayList<>();
    8882        int pos = 0;
    8883        while (pos < strLen - closeLen) {
    8884            int start = str.indexOf(open, pos);
    8885            if (start < 0) {
    8886                break;
    8887            }
    8888            start += openLen;
    8889            final int end = str.indexOf(close, start);
    8890            if (end < 0) {
    8891                break;
    8892            }
    8893            list.add(str.substring(start, end));
    8894            pos = end + closeLen;
    8895        }
    8896        if (list.isEmpty()) {
    8897            return null;
    8898        }
    8899        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    8900    }
    8901
    8902    /**
    8903     * Swaps the case of a String changing upper and title case to
    8904     * lower case, and lower case to upper case.
    8905     *
    8906     * <ul>
    8907     *  <li>Upper case character converts to Lower case</li>
    8908     *  <li>Title case character converts to Lower case</li>
    8909     *  <li>Lower case character converts to Upper case</li>
    8910     * </ul>
    8911     *
    8912     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
    8913     * A {@code null} input String returns {@code null}.</p>
    8914     *
    8915     * <pre>
    8916     * StringUtils.swapCase(null)                 = null
    8917     * StringUtils.swapCase("")                   = ""
    8918     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    8919     * </pre>
    8920     *
    8921     * <p>NOTE: This method changed in Lang version 2.0.
    8922     * It no longer performs a word based algorithm.
    8923     * If you only use ASCII, you will notice no change.
    8924     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
    8925     *
    8926     * @param str  the String to swap case, may be null
    8927     * @return the changed String, {@code null} if null String input
    8928     */
    8929    public static String swapCase(final String str) {
    8930        if (isEmpty(str)) {
    8931            return str;
    8932        }
    8933
    8934        final int strLen = str.length();
    8935        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    8936        int outOffset = 0;
    8937        for (int i = 0; i < strLen; ) {
    8938            final int oldCodepoint = str.codePointAt(i);
    8939            final int newCodePoint;
    8940            if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
    8941                newCodePoint = Character.toLowerCase(oldCodepoint);
    8942            } else if (Character.isLowerCase(oldCodepoint)) {
    8943                newCodePoint = Character.toUpperCase(oldCodepoint);
    8944            } else {
    8945                newCodePoint = oldCodepoint;
    8946            }
    8947            newCodePoints[outOffset++] = newCodePoint;
    8948            i += Character.charCount(newCodePoint);
    8949         }
    8950        return new String(newCodePoints, 0, outOffset);
    8951    }
    8952
    8953    /**
    8954     * Converts a {@link CharSequence} into an array of code points.
    8955     *
    8956     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
    8957     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
    8958     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
    8959     *
    8960     * <pre>
    8961     * StringUtils.toCodePoints(null)   =  null
    8962     * StringUtils.toCodePoints("")     =  []  // empty array
    8963     * </pre>
    8964     *
    8965     * @param cs the character sequence to convert
    8966     * @return an array of code points
    8967     * @since 3.6
    8968     */
    8969    public static int[] toCodePoints(final CharSequence cs) {
    8970        if (cs == null) {
    8971            return null;
    8972        }
    8973        if (cs.length() == 0) {
    8974            return ArrayUtils.EMPTY_INT_ARRAY;
    8975        }
    8976
    8977        final String s = cs.toString();
    8978        final int[] result = new int[s.codePointCount(0, s.length())];
    8979        int index = 0;
    8980        for (int i = 0; i < result.length; i++) {
    8981            result[i] = s.codePointAt(index);
    8982            index += Character.charCount(result[i]);
    8983        }
    8984        return result;
    8985    }
    8986
    8987    /**
    8988     * Converts a {@code byte[]} to a String using the specified character encoding.
    8989     *
    8990     * @param bytes
    8991     *            the byte array to read from
    8992     * @param charset
    8993     *            the encoding to use, if null then use the platform default
    8994     * @return a new String
    8995     * @throws NullPointerException
    8996     *             if {@code bytes} is null
    8997     * @since 3.2
    8998     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
    8999     */
    9000    public static String toEncodedString(final byte[] bytes, final Charset charset) {
    9001        return new String(bytes, Charsets.toCharset(charset));
    9002    }
    9003
    9004    /**
    9005     * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
    9006     *
    9007     * @param source A source String or null.
    9008     * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
    9009     * @since 3.10
    9010     */
    9011    public static String toRootLowerCase(final String source) {
    9012        return source == null ? null : source.toLowerCase(Locale.ROOT);
    9013    }
    9014
    9015    /**
    9016     * Converts the given source String as a upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
    9017     *
    9018     * @param source A source String or null.
    9019     * @return the given source String as a upper-case using the {@link Locale#ROOT} locale or null.
    9020     * @since 3.10
    9021     */
    9022    public static String toRootUpperCase(final String source) {
    9023        return source == null ? null : source.toUpperCase(Locale.ROOT);
    9024    }
    9025
    9026    /**
    9027     * Converts a {@code byte[]} to a String using the specified character encoding.
    9028     *
    9029     * @param bytes
    9030     *            the byte array to read from
    9031     * @param charsetName
    9032     *            the encoding to use, if null then use the platform default
    9033     * @return a new String
    9034     * @throws UnsupportedEncodingException
    9035     *             Never thrown
    9036     * @throws NullPointerException
    9037     *             if the input is null
    9038     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
    9039     * @since 3.1
    9040     */
    9041    @Deprecated
    9042    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
    9043        return new String(bytes, Charsets.toCharset(charsetName));
    9044    }
    9045
    9046    private static String toStringOrEmpty(final Object obj) {
    9047        return Objects.toString(obj, EMPTY);
    9048    }
    9049
    9050    /**
    9051     * Removes control characters (char &lt;= 32) from both
    9052     * ends of this String, handling {@code null} by returning
    9053     * {@code null}.
    9054     *
    9055     * <p>The String is trimmed using {@link String#trim()}.
    9056     * Trim removes start and end characters &lt;= 32.
    9057     * To strip whitespace use {@link #strip(String)}.</p>
    9058     *
    9059     * <p>To trim your choice of characters, use the
    9060     * {@link #strip(String, String)} methods.</p>
    9061     *
    9062     * <pre>
    9063     * StringUtils.trim(null)          = null
    9064     * StringUtils.trim("")            = ""
    9065     * StringUtils.trim("     ")       = ""
    9066     * StringUtils.trim("abc")         = "abc"
    9067     * StringUtils.trim("    abc    ") = "abc"
    9068     * </pre>
    9069     *
    9070     * @param str  the String to be trimmed, may be null
    9071     * @return the trimmed string, {@code null} if null String input
    9072     */
    9073    public static String trim(final String str) {
    9074        return str == null ? null : str.trim();
    9075    }
    9076
    9077    /**
    9078     * Removes control characters (char &lt;= 32) from both
    9079     * ends of this String returning an empty String ("") if the String
    9080     * is empty ("") after the trim or if it is {@code null}.
    9081     *
    9082     * <p>The String is trimmed using {@link String#trim()}.
    9083     * Trim removes start and end characters &lt;= 32.
    9084     * To strip whitespace use {@link #stripToEmpty(String)}.
    9085     *
    9086     * <pre>
    9087     * StringUtils.trimToEmpty(null)          = ""
    9088     * StringUtils.trimToEmpty("")            = ""
    9089     * StringUtils.trimToEmpty("     ")       = ""
    9090     * StringUtils.trimToEmpty("abc")         = "abc"
    9091     * StringUtils.trimToEmpty("    abc    ") = "abc"
    9092     * </pre>
    9093     *
    9094     * @param str  the String to be trimmed, may be null
    9095     * @return the trimmed String, or an empty String if {@code null} input
    9096     * @since 2.0
    9097     */
    9098    public static String trimToEmpty(final String str) {
    9099        return str == null ? EMPTY : str.trim();
    9100    }
    9101
    9102    /**
    9103     * Removes control characters (char &lt;= 32) from both
    9104     * ends of this String returning {@code null} if the String is
    9105     * empty ("") after the trim or if it is {@code null}.
    9106     *
    9107     * <p>The String is trimmed using {@link String#trim()}.
    9108     * Trim removes start and end characters &lt;= 32.
    9109     * To strip whitespace use {@link #stripToNull(String)}.
    9110     *
    9111     * <pre>
    9112     * StringUtils.trimToNull(null)          = null
    9113     * StringUtils.trimToNull("")            = null
    9114     * StringUtils.trimToNull("     ")       = null
    9115     * StringUtils.trimToNull("abc")         = "abc"
    9116     * StringUtils.trimToNull("    abc    ") = "abc"
    9117     * </pre>
    9118     *
    9119     * @param str  the String to be trimmed, may be null
    9120     * @return the trimmed String,
    9121     *  {@code null} if only chars &lt;= 32, empty or null String input
    9122     * @since 2.0
    9123     */
    9124    public static String trimToNull(final String str) {
    9125        final String ts = trim(str);
    9126        return isEmpty(ts) ? null : ts;
    9127    }
    9128
    9129    /**
    9130     * Truncates a String. This will turn
    9131     * "Now is the time for all good men" into "Now is the time for".
    9132     *
    9133     * <p>Specifically:</p>
    9134     * <ul>
    9135     *   <li>If {@code str} is less than {@code maxWidth} characters
    9136     *       long, return it.</li>
    9137     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
    9138     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    9139     *       {@link IllegalArgumentException}.</li>
    9140     *   <li>In no case will it return a String of length greater than
    9141     *       {@code maxWidth}.</li>
    9142     * </ul>
    9143     *
    9144     * <pre>
    9145     * StringUtils.truncate(null, 0)       = null
    9146     * StringUtils.truncate(null, 2)       = null
    9147     * StringUtils.truncate("", 4)         = ""
    9148     * StringUtils.truncate("abcdefg", 4)  = "abcd"
    9149     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
    9150     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
    9151     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
    9152     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
    9153     * </pre>
    9154     *
    9155     * @param str  the String to truncate, may be null
    9156     * @param maxWidth  maximum length of result String, must be positive
    9157     * @return truncated String, {@code null} if null String input
    9158     * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
    9159     * @since 3.5
    9160     */
    9161    public static String truncate(final String str, final int maxWidth) {
    9162        return truncate(str, 0, maxWidth);
    9163    }
    9164
    9165    /**
    9166     * Truncates a String. This will turn
    9167     * "Now is the time for all good men" into "is the time for all".
    9168     *
    9169     * <p>Works like {@code truncate(String, int)}, but allows you to specify
    9170     * a "left edge" offset.
    9171     *
    9172     * <p>Specifically:</p>
    9173     * <ul>
    9174     *   <li>If {@code str} is less than {@code maxWidth} characters
    9175     *       long, return it.</li>
    9176     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
    9177     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    9178     *       {@link IllegalArgumentException}.</li>
    9179     *   <li>If {@code offset} is less than {@code 0}, throw an
    9180     *       {@link IllegalArgumentException}.</li>
    9181     *   <li>In no case will it return a String of length greater than
    9182     *       {@code maxWidth}.</li>
    9183     * </ul>
    9184     *
    9185     * <pre>
    9186     * StringUtils.truncate(null, 0, 0) = null
    9187     * StringUtils.truncate(null, 2, 4) = null
    9188     * StringUtils.truncate("", 0, 10) = ""
    9189     * StringUtils.truncate("", 2, 10) = ""
    9190     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
    9191     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
    9192     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
    9193     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
    9194     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
    9195     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
    9196     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
    9197     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
    9198     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
    9199     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
    9200     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
    9201     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
    9202     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
    9203     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
    9204     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
    9205     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
    9206     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
    9207     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
    9208     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
    9209     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
    9210     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
    9211     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
    9212     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
    9213     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
    9214     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
    9215     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
    9216     * </pre>
    9217     *
    9218     * @param str  the String to truncate, may be null
    9219     * @param offset  left edge of source String
    9220     * @param maxWidth  maximum length of result String, must be positive
    9221     * @return truncated String, {@code null} if null String input
    9222     * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
    9223     * @since 3.5
    9224     */
    9225    public static String truncate(final String str, final int offset, final int maxWidth) {
    9226        if (offset < 0) {
    9227            throw new IllegalArgumentException("offset cannot be negative");
    9228        }
    9229        if (maxWidth < 0) {
    9230            throw new IllegalArgumentException("maxWith cannot be negative");
    9231        }
    9232        if (str == null) {
    9233            return null;
    9234        }
    9235        if (offset > str.length()) {
    9236            return EMPTY;
    9237        }
    9238        if (str.length() > maxWidth) {
    9239            final int ix = Math.min(offset + maxWidth, str.length());
    9240            return str.substring(offset, ix);
    9241        }
    9242        return str.substring(offset);
    9243    }
    9244
    9245    /**
    9246     * Uncapitalizes a String, changing the first character to lower case as
    9247     * per {@link Character#toLowerCase(int)}. No other characters are changed.
    9248     *
    9249     * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
    9250     * A {@code null} input String returns {@code null}.</p>
    9251     *
    9252     * <pre>
    9253     * StringUtils.uncapitalize(null)  = null
    9254     * StringUtils.uncapitalize("")    = ""
    9255     * StringUtils.uncapitalize("cat") = "cat"
    9256     * StringUtils.uncapitalize("Cat") = "cat"
    9257     * StringUtils.uncapitalize("CAT") = "cAT"
    9258     * </pre>
    9259     *
    9260     * @param str the String to uncapitalize, may be null
    9261     * @return the uncapitalized String, {@code null} if null String input
    9262     * @see org.apache.commons.text.WordUtils#uncapitalize(String)
    9263     * @see #capitalize(String)
    9264     * @since 2.0
    9265     */
    9266    public static String uncapitalize(final String str) {
    9267        final int strLen = length(str);
    9268        if (strLen == 0) {
    9269            return str;
    9270        }
    9271
    9272        final int firstCodePoint = str.codePointAt(0);
    9273        final int newCodePoint = Character.toLowerCase(firstCodePoint);
    9274        if (firstCodePoint == newCodePoint) {
    9275            // already capitalized
    9276            return str;
    9277        }
    9278
    9279        final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
    9280        int outOffset = 0;
    9281        newCodePoints[outOffset++] = newCodePoint; // copy the first code point
    9282        for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) {
    9283            final int codePoint = str.codePointAt(inOffset);
    9284            newCodePoints[outOffset++] = codePoint; // copy the remaining ones
    9285            inOffset += Character.charCount(codePoint);
    9286         }
    9287        return new String(newCodePoints, 0, outOffset);
    9288    }
    9289
    9290    /**
    9291     * Unwraps a given string from a character.
    9292     *
    9293     * <pre>
    9294     * StringUtils.unwrap(null, null)         = null
    9295     * StringUtils.unwrap(null, '\0')         = null
    9296     * StringUtils.unwrap(null, '1')          = null
    9297     * StringUtils.unwrap("a", 'a')           = "a"
    9298     * StringUtils.unwrap("aa", 'a')           = ""
    9299     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
    9300     * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
    9301     * StringUtils.unwrap("A", '#')           = "A"
    9302     * StringUtils.unwrap("#A", '#')          = "#A"
    9303     * StringUtils.unwrap("A#", '#')          = "A#"
    9304     * </pre>
    9305     *
    9306     * @param str
    9307     *          the String to be unwrapped, can be null
    9308     * @param wrapChar
    9309     *          the character used to unwrap
    9310     * @return unwrapped String or the original string
    9311     *          if it is not quoted properly with the wrapChar
    9312     * @since 3.6
    9313     */
    9314    public static String unwrap(final String str, final char wrapChar) {
    9315        if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
    9316            return str;
    9317        }
    9318
    9319        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
    9320            final int startIndex = 0;
    9321            final int endIndex = str.length() - 1;
    9322
    9323            return str.substring(startIndex + 1, endIndex);
    9324        }
    9325
    9326        return str;
    9327    }
    9328
    9329    /**
    9330     * Unwraps a given string from another string.
    9331     *
    9332     * <pre>
    9333     * StringUtils.unwrap(null, null)         = null
    9334     * StringUtils.unwrap(null, "")           = null
    9335     * StringUtils.unwrap(null, "1")          = null
    9336     * StringUtils.unwrap("a", "a")           = "a"
    9337     * StringUtils.unwrap("aa", "a")          = ""
    9338     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
    9339     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
    9340     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
    9341     * StringUtils.unwrap("A", "#")           = "A"
    9342     * StringUtils.unwrap("#A", "#")          = "#A"
    9343     * StringUtils.unwrap("A#", "#")          = "A#"
    9344     * </pre>
    9345     *
    9346     * @param str
    9347     *          the String to be unwrapped, can be null
    9348     * @param wrapToken
    9349     *          the String used to unwrap
    9350     * @return unwrapped String or the original string
    9351     *          if it is not quoted properly with the wrapToken
    9352     * @since 3.6
    9353     */
    9354    public static String unwrap(final String str, final String wrapToken) {
    9355        if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
    9356            return str;
    9357        }
    9358
    9359        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
    9360            return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
    9361        }
    9362
    9363        return str;
    9364    }
    9365
    9366    /**
    9367     * Converts a String to upper case as per {@link String#toUpperCase()}.
    9368     *
    9369     * <p>A {@code null} input String returns {@code null}.</p>
    9370     *
    9371     * <pre>
    9372     * StringUtils.upperCase(null)  = null
    9373     * StringUtils.upperCase("")    = ""
    9374     * StringUtils.upperCase("aBc") = "ABC"
    9375     * </pre>
    9376     *
    9377     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
    9378     * the result of this method is affected by the current locale.
    9379     * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
    9380     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    9381     *
    9382     * @param str  the String to upper case, may be null
    9383     * @return the upper-cased String, {@code null} if null String input
    9384     */
    9385    public static String upperCase(final String str) {
    9386        if (str == null) {
    9387            return null;
    9388        }
    9389        return str.toUpperCase();
    9390    }
    9391
    9392    /**
    9393     * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
    9394     *
    9395     * <p>A {@code null} input String returns {@code null}.</p>
    9396     *
    9397     * <pre>
    9398     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    9399     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    9400     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    9401     * </pre>
    9402     *
    9403     * @param str  the String to upper case, may be null
    9404     * @param locale  the locale that defines the case transformation rules, must not be null
    9405     * @return the upper-cased String, {@code null} if null String input
    9406     * @since 2.5
    9407     */
    9408    public static String upperCase(final String str, final Locale locale) {
    9409        if (str == null) {
    9410            return null;
    9411        }
    9412        return str.toUpperCase(LocaleUtils.toLocale(locale));
    9413    }
    9414
    9415    /**
    9416     * Returns the string representation of the {@code char} array or null.
    9417     *
    9418     * @param value the character array.
    9419     * @return a String or null
    9420     * @see String#valueOf(char[])
    9421     * @since 3.9
    9422     */
    9423    public static String valueOf(final char[] value) {
    9424        return value == null ? null : String.valueOf(value);
    9425    }
    9426
    9427    /**
    9428     * Wraps a string with a char.
    9429     *
    9430     * <pre>
    9431     * StringUtils.wrap(null, *)        = null
    9432     * StringUtils.wrap("", *)          = ""
    9433     * StringUtils.wrap("ab", '\0')     = "ab"
    9434     * StringUtils.wrap("ab", 'x')      = "xabx"
    9435     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9436     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
    9437     * </pre>
    9438     *
    9439     * @param str
    9440     *            the string to be wrapped, may be {@code null}
    9441     * @param wrapWith
    9442     *            the char that will wrap {@code str}
    9443     * @return the wrapped string, or {@code null} if {@code str == null}
    9444     * @since 3.4
    9445     */
    9446    public static String wrap(final String str, final char wrapWith) {
    9447
    9448        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9449            return str;
    9450        }
    9451
    9452        return wrapWith + str + wrapWith;
    9453    }
    9454
    9455    /**
    9456     * Wraps a String with another String.
    9457     *
    9458     * <p>
    9459     * A {@code null} input String returns {@code null}.
    9460     * </p>
    9461     *
    9462     * <pre>
    9463     * StringUtils.wrap(null, *)         = null
    9464     * StringUtils.wrap("", *)           = ""
    9465     * StringUtils.wrap("ab", null)      = "ab"
    9466     * StringUtils.wrap("ab", "x")       = "xabx"
    9467     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9468     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
    9469     * StringUtils.wrap("ab", "'")       = "'ab'"
    9470     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
    9471     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9472     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9473     * </pre>
    9474     *
    9475     * @param str
    9476     *            the String to be wrapper, may be null
    9477     * @param wrapWith
    9478     *            the String that will wrap str
    9479     * @return wrapped String, {@code null} if null String input
    9480     * @since 3.4
    9481     */
    9482    public static String wrap(final String str, final String wrapWith) {
    9483
    9484        if (isEmpty(str) || isEmpty(wrapWith)) {
    9485            return str;
    9486        }
    9487
    9488        return wrapWith.concat(str).concat(wrapWith);
    9489    }
    9490
    9491    /**
    9492     * Wraps a string with a char if that char is missing from the start or end of the given string.
    9493     *
    9494     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
    9495     *
    9496     * <pre>
    9497     * StringUtils.wrapIfMissing(null, *)        = null
    9498     * StringUtils.wrapIfMissing("", *)          = ""
    9499     * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
    9500     * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
    9501     * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
    9502     * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
    9503     * StringUtils.wrapIfMissing("/", '/')  = "/"
    9504     * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
    9505     * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
    9506     * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
    9507     * </pre>
    9508     *
    9509     * @param str
    9510     *            the string to be wrapped, may be {@code null}
    9511     * @param wrapWith
    9512     *            the char that will wrap {@code str}
    9513     * @return the wrapped string, or {@code null} if {@code str == null}
    9514     * @since 3.5
    9515     */
    9516    public static String wrapIfMissing(final String str, final char wrapWith) {
    9517        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9518            return str;
    9519        }
    9520        final boolean wrapStart = str.charAt(0) != wrapWith;
    9521        final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
    9522        if (!wrapStart && !wrapEnd) {
    9523            return str;
    9524        }
    9525
    9526        final StringBuilder builder = new StringBuilder(str.length() + 2);
    9527        if (wrapStart) {
    9528            builder.append(wrapWith);
    9529        }
    9530        builder.append(str);
    9531        if (wrapEnd) {
    9532            builder.append(wrapWith);
    9533        }
    9534        return builder.toString();
    9535    }
    9536
    9537    /**
    9538     * Wraps a string with a string if that string is missing from the start or end of the given string.
    9539     *
    9540     * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
    9541     *
    9542     * <pre>
    9543     * StringUtils.wrapIfMissing(null, *)         = null
    9544     * StringUtils.wrapIfMissing("", *)           = ""
    9545     * StringUtils.wrapIfMissing("ab", null)      = "ab"
    9546     * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
    9547     * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
    9548     * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
    9549     * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
    9550     * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
    9551     * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
    9552     * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
    9553     * StringUtils.wrapIfMissing("/", "/")  = "/"
    9554     * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
    9555     * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
    9556     * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
    9557     * </pre>
    9558     *
    9559     * @param str
    9560     *            the string to be wrapped, may be {@code null}
    9561     * @param wrapWith
    9562     *            the string that will wrap {@code str}
    9563     * @return the wrapped string, or {@code null} if {@code str == null}
    9564     * @since 3.5
    9565     */
    9566    public static String wrapIfMissing(final String str, final String wrapWith) {
    9567        if (isEmpty(str) || isEmpty(wrapWith)) {
    9568            return str;
    9569        }
    9570
    9571        final boolean wrapStart = !str.startsWith(wrapWith);
    9572        final boolean wrapEnd = !str.endsWith(wrapWith);
    9573        if (!wrapStart && !wrapEnd) {
    9574            return str;
    9575        }
    9576
    9577        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
    9578        if (wrapStart) {
    9579            builder.append(wrapWith);
    9580        }
    9581        builder.append(str);
    9582        if (wrapEnd) {
    9583            builder.append(wrapWith);
    9584        }
    9585        return builder.toString();
    9586    }
    9587
    9588    /**
    9589     * {@link StringUtils} instances should NOT be constructed in
    9590     * standard programming. Instead, the class should be used as
    9591     * {@code StringUtils.trim(" foo ");}.
    9592     *
    9593     * <p>This constructor is public to permit tools that require a JavaBean
    9594     * instance to operate.</p>
    9595     *
    9596     * @deprecated TODO Make private in 4.0.
    9597     */
    9598    @Deprecated
    9599    public StringUtils() {
    9600        // empty
    9601    }
    9602
    9603}