    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.Iterator;
    025import java.util.List;
    026import java.util.Locale;
    027import java.util.Objects;
    028import java.util.regex.Pattern;
    029
    030/**
    031 * <p>Operations on {@link java.lang.String} that are
    032 * {@code null} safe.</p>
    033 *
    034 * <ul>
    035 *  <li><b>IsEmpty/IsBlank</b>
    036 *      - checks if a String contains text</li>
    037 *  <li><b>Trim/Strip</b>
    038 *      - removes leading and trailing whitespace</li>
    039 *  <li><b>Equals/Compare</b>
    040 *      - compares two strings null-safe</li>
    041 *  <li><b>startsWith</b>
    042 *      - check if a String starts with a prefix null-safe</li>
    043 *  <li><b>endsWith</b>
    044 *      - check if a String ends with a suffix null-safe</li>
    045 *  <li><b>IndexOf/LastIndexOf/Contains</b>
    046 *      - null-safe index-of checks
    047 *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
    048 *      - index-of any of a set of Strings</li>
    049 *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
    050 *      - does String contains only/none/any of these characters</li>
    051 *  <li><b>Substring/Left/Right/Mid</b>
    052 *      - null-safe substring extractions</li>
    053 *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
    054 *      - substring extraction relative to other strings</li>
    055 *  <li><b>Split/Join</b>
    056 *      - splits a String into an array of substrings and vice versa</li>
    057 *  <li><b>Remove/Delete</b>
    058 *      - removes part of a String</li>
    059 *  <li><b>Replace/Overlay</b>
    060 *      - Searches a String and replaces one String with another</li>
    061 *  <li><b>Chomp/Chop</b>
    062 *      - removes the last part of a String</li>
    063 *  <li><b>AppendIfMissing</b>
    064 *      - appends a suffix to the end of the String if not present</li>
    065 *  <li><b>PrependIfMissing</b>
    066 *      - prepends a prefix to the start of the String if not present</li>
    067 *  <li><b>LeftPad/RightPad/Center/Repeat</b>
    068 *      - pads a String</li>
    069 *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
    070 *      - changes the case of a String</li>
    071 *  <li><b>CountMatches</b>
    072 *      - counts the number of occurrences of one String in another</li>
    073 *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
    074 *      - checks the characters in a String</li>
    075 *  <li><b>DefaultString</b>
    076 *      - protects against a null input String</li>
    077 *  <li><b>Rotate</b>
    078 *      - rotate (circular shift) a String</li>
    079 *  <li><b>Reverse/ReverseDelimited</b>
    080 *      - reverses a String</li>
    081 *  <li><b>Abbreviate</b>
    082 *      - abbreviates a string using ellipsis or another given String</li>
    083 *  <li><b>Difference</b>
    084 *      - compares Strings and reports on their differences</li>
    085 *  <li><b>LevenshteinDistance</b>
    086 *      - the number of changes needed to change one String into another</li>
    087 * </ul>
    088 *
    089 * <p>The {@code StringUtils} class defines certain words related to
    090 * String handling.</p>
    091 *
    092 * <ul>
    093 *  <li>null - {@code null}</li>
    094 *  <li>empty - a zero-length string ({@code ""})</li>
    095 *  <li>space - the space character ({@code ' '}, char 32)</li>
    096 *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
    097 *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
    098 * </ul>
    099 *
    100 * <p>{@code StringUtils} handles {@code null} input Strings quietly.
    101 * That is to say that a {@code null} input will return {@code null}.
    102 * Where a {@code boolean} or {@code int} is being returned
    103 * details vary by method.</p>
    104 *
    105 * <p>A side effect of the {@code null} handling is that a
    106 * {@code NullPointerException} should be considered a bug in
    107 * {@code StringUtils}.</p>
    108 *
    109 * <p>Methods in this class give sample code to explain their operation.
    110 * The symbol {@code *} is used to indicate any input including {@code null}.</p>
    111 *
    112 * <p>#ThreadSafe#</p>
    113 * @see java.lang.String
    114 * @since 1.0
    115 */
    116//@Immutable
    117public class StringUtils {
    118
    119    private static final int STRING_BUILDER_SIZE = 256;
    120
    121    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
    122    // Whitespace:
    123    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
    124    // where WHITESPACE is a string of all whitespace characters
    125    //
    126    // Character access:
    127    // String.charAt(n) versus toCharArray(), then array[n]
    128    // String.charAt(n) is about 15% worse for a 10K string
    129    // They are about equal for a length 50 string
    130    // String.charAt(n) is about 4 times better for a length 3 string
    131    // String.charAt(n) is best bet overall
    132    //
    133    // Append:
    134    // String.concat about twice as fast as StringBuffer.append
    135    // (not sure who tested this)
    136
    137    /**
    138     * A String for a space character.
    139     *
    140     * @since 3.2
    141     */
    142    public static final String SPACE = " ";
    143
    144    /**
    145     * The empty String {@code ""}.
    146     * @since 2.0
    147     */
    148    public static final String EMPTY = "";
    149
    150    /**
    151     * A String for linefeed LF ("\n").
    152     *
    153     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    154     *      for Character and String Literals</a>
    155     * @since 3.2
    156     */
    157    public static final String LF = "\n";
    158
    159    /**
    160     * A String for carriage return CR ("\r").
    161     *
    162     * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
    163     *      for Character and String Literals</a>
    164     * @since 3.2
    165     */
    166    public static final String CR = "\r";
    167
    168    /**
    169     * Represents a failed index search.
    170     * @since 2.1
    171     */
    172    public static final int INDEX_NOT_FOUND = -1;
    173
    174    /**
    175     * <p>The maximum size to which the padding constant(s) can expand.</p>
    176     */
    177    private static final int PAD_LIMIT = 8192;
    178
    179    /**
    180     * <p>{@code StringUtils} instances should NOT be constructed in
    181     * standard programming. Instead, the class should be used as
    182     * {@code StringUtils.trim(" foo ");}.</p>
    183     *
    184     * <p>This constructor is public to permit tools that require a JavaBean
    185     * instance to operate.</p>
    186     */
    187    public StringUtils() {
    188        super();
    189    }
    190
    191    // Empty checks
    192    //-----------------------------------------------------------------------
    193    /**
    194     * <p>Checks if a CharSequence is empty ("") or null.</p>
    195     *
    196     * <pre>
    197     * StringUtils.isEmpty(null)      = true
    198     * StringUtils.isEmpty("")        = true
    199     * StringUtils.isEmpty(" ")       = false
    200     * StringUtils.isEmpty("bob")     = false
    201     * StringUtils.isEmpty("  bob  ") = false
    202     * </pre>
    203     *
    204     * <p>NOTE: This method changed in Lang version 2.0.
    205     * It no longer trims the CharSequence.
    206     * That functionality is available in isBlank().</p>
    207     *
    208     * @param cs  the CharSequence to check, may be null
    209     * @return {@code true} if the CharSequence is empty or null
    210     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    211     */
    212    public static boolean isEmpty(final CharSequence cs) {
    213        return cs == null || cs.length() == 0;
    214    }
    215
    216    /**
    217     * <p>Checks if a CharSequence is not empty ("") and not null.</p>
    218     *
    219     * <pre>
    220     * StringUtils.isNotEmpty(null)      = false
    221     * StringUtils.isNotEmpty("")        = false
    222     * StringUtils.isNotEmpty(" ")       = true
    223     * StringUtils.isNotEmpty("bob")     = true
    224     * StringUtils.isNotEmpty("  bob  ") = true
    225     * </pre>
    226     *
    227     * @param cs  the CharSequence to check, may be null
    228     * @return {@code true} if the CharSequence is not empty and not null
    229     * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    230     */
    231    public static boolean isNotEmpty(final CharSequence cs) {
    232        return !isEmpty(cs);
    233    }
    234
    235    /**
    236     * <p>Checks if any of the CharSequences are empty ("") or null.</p>
    237     *
    238     * <pre>
    239     * StringUtils.isAnyEmpty((String) null)    = true
    240     * StringUtils.isAnyEmpty((String[]) null)  = false
    241     * StringUtils.isAnyEmpty(null, "foo")      = true
    242     * StringUtils.isAnyEmpty("", "bar")        = true
    243     * StringUtils.isAnyEmpty("bob", "")        = true
    244     * StringUtils.isAnyEmpty("  bob  ", null)  = true
    245     * StringUtils.isAnyEmpty(" ", "bar")       = false
    246     * StringUtils.isAnyEmpty("foo", "bar")     = false
    247     * StringUtils.isAnyEmpty(new String[]{})   = false
    248     * StringUtils.isAnyEmpty(new String[]{""}) = true
    249     * </pre>
    250     *
    251     * @param css  the CharSequences to check, may be null or empty
    252     * @return {@code true} if any of the CharSequences are empty or null
    253     * @since 3.2
    254     */
    255    public static boolean isAnyEmpty(final CharSequence... css) {
    256      if (ArrayUtils.isEmpty(css)) {
    257        return false;
    258      }
    259      for (final CharSequence cs : css){
    260        if (isEmpty(cs)) {
    261          return true;
    262        }
    263      }
    264      return false;
    265    }
    266
    267    /**
    268     * <p>Checks if none of the CharSequences are empty ("") or null.</p>
    269     *
    270     * <pre>
    271     * StringUtils.isNoneEmpty((String) null)    = false
    272     * StringUtils.isNoneEmpty((String[]) null)  = true
    273     * StringUtils.isNoneEmpty(null, "foo")      = false
    274     * StringUtils.isNoneEmpty("", "bar")        = false
    275     * StringUtils.isNoneEmpty("bob", "")        = false
    276     * StringUtils.isNoneEmpty("  bob  ", null)  = false
    277     * StringUtils.isNoneEmpty(new String[] {})  = true
    278     * StringUtils.isNoneEmpty(new String[]{""}) = false
    279     * StringUtils.isNoneEmpty(" ", "bar")       = true
    280     * StringUtils.isNoneEmpty("foo", "bar")     = true
    281     * </pre>
    282     *
    283     * @param css  the CharSequences to check, may be null or empty
    284     * @return {@code true} if none of the CharSequences are empty or null
    285     * @since 3.2
    286     */
    287    public static boolean isNoneEmpty(final CharSequence... css) {
    288      return !isAnyEmpty(css);
    289    }
    290
    291    /**
    292     * <p>Checks if all of the CharSequences are empty ("") or null.</p>
    293     *
    294     * <pre>
    295     * StringUtils.isAllEmpty(null)             = true
    296     * StringUtils.isAllEmpty(null, "")         = true
    297     * StringUtils.isAllEmpty(new String[] {})  = true
    298     * StringUtils.isAllEmpty(null, "foo")      = false
    299     * StringUtils.isAllEmpty("", "bar")        = false
    300     * StringUtils.isAllEmpty("bob", "")        = false
    301     * StringUtils.isAllEmpty("  bob  ", null)  = false
    302     * StringUtils.isAllEmpty(" ", "bar")       = false
    303     * StringUtils.isAllEmpty("foo", "bar")     = false
    304     * </pre>
    305     *
    306     * @param css  the CharSequences to check, may be null or empty
    307     * @return {@code true} if all of the CharSequences are empty or null
    308     * @since 3.6
    309     */
    310    public static boolean isAllEmpty(final CharSequence... css) {
    311        if (ArrayUtils.isEmpty(css)) {
    312            return true;
    313        }
    314        for (final CharSequence cs : css) {
    315            if (isNotEmpty(cs)) {
    316                return false;
    317            }
    318        }
    319        return true;
    320    }
    321
    322    /**
    323     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
    324     *
    325     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    326     *
    327     * <pre>
    328     * StringUtils.isBlank(null)      = true
    329     * StringUtils.isBlank("")        = true
    330     * StringUtils.isBlank(" ")       = true
    331     * StringUtils.isBlank("bob")     = false
    332     * StringUtils.isBlank("  bob  ") = false
    333     * </pre>
    334     *
    335     * @param cs  the CharSequence to check, may be null
    336     * @return {@code true} if the CharSequence is null, empty or whitespace only
    337     * @since 2.0
    338     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    339     */
    340    public static boolean isBlank(final CharSequence cs) {
    341        int strLen;
    342        if (cs == null || (strLen = cs.length()) == 0) {
    343            return true;
    344        }
    345        for (int i = 0; i < strLen; i++) {
    346            if (!Character.isWhitespace(cs.charAt(i))) {
    347                return false;
    348            }
    349        }
    350        return true;
    351    }
    352
    353    /**
    354     * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
    355     *
    356     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    357     *
    358     * <pre>
    359     * StringUtils.isNotBlank(null)      = false
    360     * StringUtils.isNotBlank("")        = false
    361     * StringUtils.isNotBlank(" ")       = false
    362     * StringUtils.isNotBlank("bob")     = true
    363     * StringUtils.isNotBlank("  bob  ") = true
    364     * </pre>
    365     *
    366     * @param cs  the CharSequence to check, may be null
    367     * @return {@code true} if the CharSequence is
    368     *  not empty and not null and not whitespace only
    369     * @since 2.0
    370     * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    371     */
    372    public static boolean isNotBlank(final CharSequence cs) {
    373        return !isBlank(cs);
    374    }
    375
    376    /**
    377     * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p>
    378     *
    379     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    380     *
    381     * <pre>
    382     * StringUtils.isAnyBlank((String) null)    = true
    383     * StringUtils.isAnyBlank((String[]) null)  = false
    384     * StringUtils.isAnyBlank(null, "foo")      = true
    385     * StringUtils.isAnyBlank(null, null)       = true
    386     * StringUtils.isAnyBlank("", "bar")        = true
    387     * StringUtils.isAnyBlank("bob", "")        = true
    388     * StringUtils.isAnyBlank("  bob  ", null)  = true
    389     * StringUtils.isAnyBlank(" ", "bar")       = true
    390     * StringUtils.isAnyBlank(new String[] {})  = false
    391     * StringUtils.isAnyBlank(new String[]{""}) = true
    392     * StringUtils.isAnyBlank("foo", "bar")     = false
    393     * </pre>
    394     *
    395     * @param css  the CharSequences to check, may be null or empty
    396     * @return {@code true} if any of the CharSequences are empty or null or whitespace only
    397     * @since 3.2
    398     */
    399    public static boolean isAnyBlank(final CharSequence... css) {
    400      if (ArrayUtils.isEmpty(css)) {
    401        return false;
    402      }
    403      for (final CharSequence cs : css){
    404        if (isBlank(cs)) {
    405          return true;
    406        }
    407      }
    408      return false;
    409    }
    410
    411    /**
    412     * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p>
    413     *
    414     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    415     *
    416     * <pre>
    417     * StringUtils.isNoneBlank((String) null)    = false
    418     * StringUtils.isNoneBlank((String[]) null)  = true
    419     * StringUtils.isNoneBlank(null, "foo")      = false
    420     * StringUtils.isNoneBlank(null, null)       = false
    421     * StringUtils.isNoneBlank("", "bar")        = false
    422     * StringUtils.isNoneBlank("bob", "")        = false
    423     * StringUtils.isNoneBlank("  bob  ", null)  = false
    424     * StringUtils.isNoneBlank(" ", "bar")       = false
    425     * StringUtils.isNoneBlank(new String[] {})  = true
    426     * StringUtils.isNoneBlank(new String[]{""}) = false
    427     * StringUtils.isNoneBlank("foo", "bar")     = true
    428     * </pre>
    429     *
    430     * @param css  the CharSequences to check, may be null or empty
    431     * @return {@code true} if none of the CharSequences are empty or null or whitespace only
    432     * @since 3.2
    433     */
    434    public static boolean isNoneBlank(final CharSequence... css) {
    435      return !isAnyBlank(css);
    436    }
    437
    438    /**
    439     * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p>
    440     *
    441     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    442     *
    443     * <pre>
    444     * StringUtils.isAllBlank(null)             = true
    445     * StringUtils.isAllBlank(null, "foo")      = false
    446     * StringUtils.isAllBlank(null, null)       = true
    447     * StringUtils.isAllBlank("", "bar")        = false
    448     * StringUtils.isAllBlank("bob", "")        = false
    449     * StringUtils.isAllBlank("  bob  ", null)  = false
    450     * StringUtils.isAllBlank(" ", "bar")       = false
    451     * StringUtils.isAllBlank("foo", "bar")     = false
    452     * StringUtils.isAllBlank(new String[] {})  = true
    453     * </pre>
    454     *
    455     * @param css  the CharSequences to check, may be null or empty
    456     * @return {@code true} if all of the CharSequences are empty or null or whitespace only
    457     * @since 3.6
    458     */
    459    public static boolean isAllBlank(final CharSequence... css) {
    460        if (ArrayUtils.isEmpty(css)) {
    461            return true;
    462        }
    463        for (final CharSequence cs : css) {
    464            if (isNotBlank(cs)) {
    465               return false;
    466            }
    467        }
    468        return true;
    469    }
    470
    471    // Trim
    472    //-----------------------------------------------------------------------
    473    /**
    474     * <p>Removes control characters (char &lt;= 32) from both
    475     * ends of this String, handling {@code null} by returning
    476     * {@code null}.</p>
    477     *
    478     * <p>The String is trimmed using {@link String#trim()}.
    479     * Trim removes start and end characters &lt;= 32.
    480     * To strip whitespace use {@link #strip(String)}.</p>
    481     *
    482     * <p>To trim your choice of characters, use the
    483     * {@link #strip(String, String)} methods.</p>
    484     *
    485     * <pre>
    486     * StringUtils.trim(null)          = null
    487     * StringUtils.trim("")            = ""
    488     * StringUtils.trim("     ")       = ""
    489     * StringUtils.trim("abc")         = "abc"
    490     * StringUtils.trim("    abc    ") = "abc"
    491     * </pre>
    492     *
    493     * @param str  the String to be trimmed, may be null
    494     * @return the trimmed string, {@code null} if null String input
    495     */
    496    public static String trim(final String str) {
    497        return str == null ? null : str.trim();
    498    }
    499
    500    /**
    501     * <p>Removes control characters (char &lt;= 32) from both
    502     * ends of this String returning {@code null} if the String is
    503     * empty ("") after the trim or if it is {@code null}.
    504     *
    505     * <p>The String is trimmed using {@link String#trim()}.
    506     * Trim removes start and end characters &lt;= 32.
    507     * To strip whitespace use {@link #stripToNull(String)}.</p>
    508     *
    509     * <pre>
    510     * StringUtils.trimToNull(null)          = null
    511     * StringUtils.trimToNull("")            = null
    512     * StringUtils.trimToNull("     ")       = null
    513     * StringUtils.trimToNull("abc")         = "abc"
    514     * StringUtils.trimToNull("    abc    ") = "abc"
    515     * </pre>
    516     *
    517     * @param str  the String to be trimmed, may be null
    518     * @return the trimmed String,
    519     *  {@code null} if only chars &lt;= 32, empty or null String input
    520     * @since 2.0
    521     */
    522    public static String trimToNull(final String str) {
    523        final String ts = trim(str);
    524        return isEmpty(ts) ? null : ts;
    525    }
    526
    527    /**
    528     * <p>Removes control characters (char &lt;= 32) from both
    529     * ends of this String returning an empty String ("") if the String
    530     * is empty ("") after the trim or if it is {@code null}.
    531     *
    532     * <p>The String is trimmed using {@link String#trim()}.
    533     * Trim removes start and end characters &lt;= 32.
    534     * To strip whitespace use {@link #stripToEmpty(String)}.</p>
    535     *
    536     * <pre>
    537     * StringUtils.trimToEmpty(null)          = ""
    538     * StringUtils.trimToEmpty("")            = ""
    539     * StringUtils.trimToEmpty("     ")       = ""
    540     * StringUtils.trimToEmpty("abc")         = "abc"
    541     * StringUtils.trimToEmpty("    abc    ") = "abc"
    542     * </pre>
    543     *
    544     * @param str  the String to be trimmed, may be null
    545     * @return the trimmed String, or an empty String if {@code null} input
    546     * @since 2.0
    547     */
    548    public static String trimToEmpty(final String str) {
    549        return str == null ? EMPTY : str.trim();
    550    }
    551
    552    /**
    553     * <p>Truncates a String. This will turn
    554     * "Now is the time for all good men" into "Now is the time for".</p>
    555     *
    556     * <p>Specifically:</p>
    557     * <ul>
    558     *   <li>If {@code str} is less than {@code maxWidth} characters
    559     *       long, return it.</li>
    560     *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
    561     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    562     *       {@code IllegalArgumentException}.</li>
    563     *   <li>In no case will it return a String of length greater than
    564     *       {@code maxWidth}.</li>
    565     * </ul>
    566     *
    567     * <pre>
    568     * StringUtils.truncate(null, 0)       = null
    569     * StringUtils.truncate(null, 2)       = null
    570     * StringUtils.truncate("", 4)         = ""
    571     * StringUtils.truncate("abcdefg", 4)  = "abcd"
    572     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
    573     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
    574     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
    575     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
    576     * </pre>
    577     *
    578     * @param str  the String to truncate, may be null
    579     * @param maxWidth  maximum length of result String, must be positive
    580     * @return truncated String, {@code null} if null String input
    581     * @since 3.5
    582     */
    583    public static String truncate(final String str, final int maxWidth) {
    584        return truncate(str, 0, maxWidth);
    585    }
    586
    587    /**
    588     * <p>Truncates a String. This will turn
    589     * "Now is the time for all good men" into "is the time for all".</p>
    590     *
    591     * <p>Works like {@code truncate(String, int)}, but allows you to specify
    592     * a "left edge" offset.
    593     *
    594     * <p>Specifically:</p>
    595     * <ul>
    596     *   <li>If {@code str} is less than {@code maxWidth} characters
    597     *       long, return it.</li>
    598     *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
    599     *   <li>If {@code maxWidth} is less than {@code 0}, throw an
    600     *       {@code IllegalArgumentException}.</li>
    601     *   <li>If {@code offset} is less than {@code 0}, throw an
    602     *       {@code IllegalArgumentException}.</li>
    603     *   <li>In no case will it return a String of length greater than
    604     *       {@code maxWidth}.</li>
    605     * </ul>
    606     *
    607     * <pre>
    608     * StringUtils.truncate(null, 0, 0) = null
    609     * StringUtils.truncate(null, 2, 4) = null
    610     * StringUtils.truncate("", 0, 10) = ""
    611     * StringUtils.truncate("", 2, 10) = ""
    612     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
    613     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
    614     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
    615     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
    616     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
    617     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij"
    618     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno"
    619     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
    620     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
    621     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
    622     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
    623     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
    624     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
    625     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
    626     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
    627     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
    628     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
    629     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
    630     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
    631     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
    632     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
    633     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
    634     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
    635     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
    636     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
    637     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
    638     * </pre>
    639     *
    640     * @param str  the String to check, may be null
    641     * @param offset  left edge of source String
    642     * @param maxWidth  maximum length of result String, must be positive
    643     * @return truncated String, {@code null} if null String input
    644     * @since 3.5
    645     */
    646    public static String truncate(final String str, final int offset, final int maxWidth) {
    647        if (offset < 0) {
    648            throw new IllegalArgumentException("offset cannot be negative");
    649        }
    650        if (maxWidth < 0) {
    651            throw new IllegalArgumentException("maxWith cannot be negative");
    652        }
    653        if (str == null) {
    654            return null;
    655        }
    656        if (offset > str.length()) {
    657            return EMPTY;
    658        }
    659        if (str.length() > maxWidth) {
    660            final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth;
    661            return str.substring(offset, ix);
    662        }
    663        return str.substring(offset);
    664    }
    665
    666    // Stripping
    667    //-----------------------------------------------------------------------
    668    /**
    669     * <p>Strips whitespace from the start and end of a String.</p>
    670     *
    671     * <p>This is similar to {@link #trim(String)} but removes whitespace.
    672     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    673     *
    674     * <p>A {@code null} input String returns {@code null}.</p>
    675     *
    676     * <pre>
    677     * StringUtils.strip(null)     = null
    678     * StringUtils.strip("")       = ""
    679     * StringUtils.strip("   ")    = ""
    680     * StringUtils.strip("abc")    = "abc"
    681     * StringUtils.strip("  abc")  = "abc"
    682     * StringUtils.strip("abc  ")  = "abc"
    683     * StringUtils.strip(" abc ")  = "abc"
    684     * StringUtils.strip(" ab c ") = "ab c"
    685     * </pre>
    686     *
    687     * @param str  the String to remove whitespace from, may be null
    688     * @return the stripped String, {@code null} if null String input
    689     */
    690    public static String strip(final String str) {
    691        return strip(str, null);
    692    }
    693
    694    /**
    695     * <p>Strips whitespace from the start and end of a String  returning
    696     * {@code null} if the String is empty ("") after the strip.</p>
    697     *
    698     * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
    699     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    700     *
    701     * <pre>
    702     * StringUtils.stripToNull(null)     = null
    703     * StringUtils.stripToNull("")       = null
    704     * StringUtils.stripToNull("   ")    = null
    705     * StringUtils.stripToNull("abc")    = "abc"
    706     * StringUtils.stripToNull("  abc")  = "abc"
    707     * StringUtils.stripToNull("abc  ")  = "abc"
    708     * StringUtils.stripToNull(" abc ")  = "abc"
    709     * StringUtils.stripToNull(" ab c ") = "ab c"
    710     * </pre>
    711     *
    712     * @param str  the String to be stripped, may be null
    713     * @return the stripped String,
    714     *  {@code null} if whitespace, empty or null String input
    715     * @since 2.0
    716     */
    717    public static String stripToNull(String str) {
    718        if (str == null) {
    719            return null;
    720        }
    721        str = strip(str, null);
    722        return str.isEmpty() ? null : str;
    723    }
    724
    725    /**
    726     * <p>Strips whitespace from the start and end of a String  returning
    727     * an empty String if {@code null} input.</p>
    728     *
    729     * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
    730     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    731     *
    732     * <pre>
    733     * StringUtils.stripToEmpty(null)     = ""
    734     * StringUtils.stripToEmpty("")       = ""
    735     * StringUtils.stripToEmpty("   ")    = ""
    736     * StringUtils.stripToEmpty("abc")    = "abc"
    737     * StringUtils.stripToEmpty("  abc")  = "abc"
    738     * StringUtils.stripToEmpty("abc  ")  = "abc"
    739     * StringUtils.stripToEmpty(" abc ")  = "abc"
    740     * StringUtils.stripToEmpty(" ab c ") = "ab c"
    741     * </pre>
    742     *
    743     * @param str  the String to be stripped, may be null
    744     * @return the trimmed String, or an empty String if {@code null} input
    745     * @since 2.0
    746     */
    747    public static String stripToEmpty(final String str) {
    748        return str == null ? EMPTY : strip(str, null);
    749    }
    750
    751    /**
    752     * <p>Strips any of a set of characters from the start and end of a String.
    753     * This is similar to {@link String#trim()} but allows the characters
    754     * to be stripped to be controlled.</p>
    755     *
    756     * <p>A {@code null} input String returns {@code null}.
    757     * An empty string ("") input returns the empty string.</p>
    758     *
    759     * <p>If the stripChars String is {@code null}, whitespace is
    760     * stripped as defined by {@link Character#isWhitespace(char)}.
    761     * Alternatively use {@link #strip(String)}.</p>
    762     *
    763     * <pre>
    764     * StringUtils.strip(null, *)          = null
    765     * StringUtils.strip("", *)            = ""
    766     * StringUtils.strip("abc", null)      = "abc"
    767     * StringUtils.strip("  abc", null)    = "abc"
    768     * StringUtils.strip("abc  ", null)    = "abc"
    769     * StringUtils.strip(" abc ", null)    = "abc"
    770     * StringUtils.strip("  abcyx", "xyz") = "  abc"
    771     * </pre>
    772     *
    773     * @param str  the String to remove characters from, may be null
    774     * @param stripChars  the characters to remove, null treated as whitespace
    775     * @return the stripped String, {@code null} if null String input
    776     */
    777    public static String strip(String str, final String stripChars) {
    778        if (isEmpty(str)) {
    779            return str;
    780        }
    781        str = stripStart(str, stripChars);
    782        return stripEnd(str, stripChars);
    783    }
    784
    785    /**
    786     * <p>Strips any of a set of characters from the start of a String.</p>
    787     *
    788     * <p>A {@code null} input String returns {@code null}.
    789     * An empty string ("") input returns the empty string.</p>
    790     *
    791     * <p>If the stripChars String is {@code null}, whitespace is
    792     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    793     *
    794     * <pre>
    795     * StringUtils.stripStart(null, *)          = null
    796     * StringUtils.stripStart("", *)            = ""
    797     * StringUtils.stripStart("abc", "")        = "abc"
    798     * StringUtils.stripStart("abc", null)      = "abc"
    799     * StringUtils.stripStart("  abc", null)    = "abc"
    800     * StringUtils.stripStart("abc  ", null)    = "abc  "
    801     * StringUtils.stripStart(" abc ", null)    = "abc "
    802     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    803     * </pre>
    804     *
    805     * @param str  the String to remove characters from, may be null
    806     * @param stripChars  the characters to remove, null treated as whitespace
    807     * @return the stripped String, {@code null} if null String input
    808     */
    809    public static String stripStart(final String str, final String stripChars) {
    810        int strLen;
    811        if (str == null || (strLen = str.length()) == 0) {
    812            return str;
    813        }
    814        int start = 0;
    815        if (stripChars == null) {
    816            while (start != strLen && Character.isWhitespace(str.charAt(start))) {
    817                start++;
    818            }
    819        } else if (stripChars.isEmpty()) {
    820            return str;
    821        } else {
    822            while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
    823                start++;
    824            }
    825        }
    826        return str.substring(start);
    827    }
    828
    829    /**
    830     * <p>Strips any of a set of characters from the end of a String.</p>
    831     *
    832     * <p>A {@code null} input String returns {@code null}.
    833     * An empty string ("") input returns the empty string.</p>
    834     *
    835     * <p>If the stripChars String is {@code null}, whitespace is
    836     * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    837     *
    838     * <pre>
    839     * StringUtils.stripEnd(null, *)          = null
    840     * StringUtils.stripEnd("", *)            = ""
    841     * StringUtils.stripEnd("abc", "")        = "abc"
    842     * StringUtils.stripEnd("abc", null)      = "abc"
    843     * StringUtils.stripEnd("  abc", null)    = "  abc"
    844     * StringUtils.stripEnd("abc  ", null)    = "abc"
    845     * StringUtils.stripEnd(" abc ", null)    = " abc"
    846     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    847     * StringUtils.stripEnd("120.00", ".0")   = "12"
    848     * </pre>
    849     *
    850     * @param str  the String to remove characters from, may be null
    851     * @param stripChars  the set of characters to remove, null treated as whitespace
    852     * @return the stripped String, {@code null} if null String input
    853     */
    854    public static String stripEnd(final String str, final String stripChars) {
    855        int end;
    856        if (str == null || (end = str.length()) == 0) {
    857            return str;
    858        }
    859
    860        if (stripChars == null) {
    861            while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
    862                end--;
    863            }
    864        } else if (stripChars.isEmpty()) {
    865            return str;
    866        } else {
    867            while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
    868                end--;
    869            }
    870        }
    871        return str.substring(0, end);
    872    }
    873
    874    // StripAll
    875    //-----------------------------------------------------------------------
    876    /**
    877     * <p>Strips whitespace from the start and end of every String in an array.
    878     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    879     *
    880     * <p>A new array is returned each time, except for length zero.
    881     * A {@code null} array will return {@code null}.
    882     * An empty array will return itself.
    883     * A {@code null} array entry will be ignored.</p>
    884     *
    885     * <pre>
    886     * StringUtils.stripAll(null)             = null
    887     * StringUtils.stripAll([])               = []
    888     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    889     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    890     * </pre>
    891     *
    892     * @param strs  the array to remove whitespace from, may be null
    893     * @return the stripped Strings, {@code null} if null array input
    894     */
    895    public static String[] stripAll(final String... strs) {
    896        return stripAll(strs, null);
    897    }
    898
    899    /**
    900     * <p>Strips any of a set of characters from the start and end of every
    901     * String in an array.</p>
    902     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    903     *
    904     * <p>A new array is returned each time, except for length zero.
    905     * A {@code null} array will return {@code null}.
    906     * An empty array will return itself.
    907     * A {@code null} array entry will be ignored.
    908     * A {@code null} stripChars will strip whitespace as defined by
    909     * {@link Character#isWhitespace(char)}.</p>
    910     *
    911     * <pre>
    912     * StringUtils.stripAll(null, *)                = null
    913     * StringUtils.stripAll([], *)                  = []
    914     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    915     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    916     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    917     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    918     * </pre>
    919     *
    920     * @param strs  the array to remove characters from, may be null
    921     * @param stripChars  the characters to remove, null treated as whitespace
    922     * @return the stripped Strings, {@code null} if null array input
    923     */
    924    public static String[] stripAll(final String[] strs, final String stripChars) {
    925        int strsLen;
    926        if (strs == null || (strsLen = strs.length) == 0) {
    927            return strs;
    928        }
    929        final String[] newArr = new String[strsLen];
    930        for (int i = 0; i < strsLen; i++) {
    931            newArr[i] = strip(strs[i], stripChars);
    932        }
    933        return newArr;
    934    }
    935
    936    /**
    937     * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
    938     * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
    939     * <p>Note that ligatures will be left as is.</p>
    940     *
    941     * <pre>
    942     * StringUtils.stripAccents(null)                = null
    943     * StringUtils.stripAccents("")                  = ""
    944     * StringUtils.stripAccents("control")           = "control"
    945     * StringUtils.stripAccents("&eacute;clair")     = "eclair"
    946     * </pre>
    947     *
    948     * @param input String to be stripped
    949     * @return input text with diacritics removed
    950     *
    951     * @since 3.0
    952     */
    953    // 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).
    954    public static String stripAccents(final String input) {
    955        if(input == null) {
    956            return null;
    957        }
    958        final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
    959        final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
    960        convertRemainingAccentCharacters(decomposed);
    961        // Note that this doesn't correctly remove ligatures...
    962        return pattern.matcher(decomposed).replaceAll(EMPTY);
    963    }
    964
    965    private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
    966        for (int i = 0; i < decomposed.length(); i++) {
    967            if (decomposed.charAt(i) == '\u0141') {
    968                decomposed.deleteCharAt(i);
    969                decomposed.insert(i, 'L');
    970            } else if (decomposed.charAt(i) == '\u0142') {
    971                decomposed.deleteCharAt(i);
    972                decomposed.insert(i, 'l');
    973            }
    974        }
    975    }
    976
    977    // Equals
    978    //-----------------------------------------------------------------------
    979    /**
    980     * <p>Compares two CharSequences, returning {@code true} if they represent
    981     * equal sequences of characters.</p>
    982     *
    983     * <p>{@code null}s are handled without exceptions. Two {@code null}
    984     * references are considered to be equal. The comparison is case sensitive.</p>
    985     *
    986     * <pre>
    987     * StringUtils.equals(null, null)   = true
    988     * StringUtils.equals(null, "abc")  = false
    989     * StringUtils.equals("abc", null)  = false
    990     * StringUtils.equals("abc", "abc") = true
    991     * StringUtils.equals("abc", "ABC") = false
    992     * </pre>
    993     *
    994     * @see Object#equals(Object)
    995     * @param cs1  the first CharSequence, may be {@code null}
    996     * @param cs2  the second CharSequence, may be {@code null}
    997     * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
    998     * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    999     */
    1000    public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
    1001        if (cs1 == cs2) {
    1002            return true;
    1003        }
    1004        if (cs1 == null || cs2 == null) {
    1005            return false;
    1006        }
    1007        if (cs1.length() != cs2.length()) {
    1008            return false;
    1009        }
    1010        if (cs1 instanceof String && cs2 instanceof String) {
    1011            return cs1.equals(cs2);
    1012        }
    1013        return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
    1014    }
    1015
    1016    /**
    1017     * <p>Compares two CharSequences, returning {@code true} if they represent
    1018     * equal sequences of characters, ignoring case.</p>
    1019     *
    1020     * <p>{@code null}s are handled without exceptions. Two {@code null}
    1021     * references are considered equal. Comparison is case insensitive.</p>
    1022     *
    1023     * <pre>
    1024     * StringUtils.equalsIgnoreCase(null, null)   = true
    1025     * StringUtils.equalsIgnoreCase(null, "abc")  = false
    1026     * StringUtils.equalsIgnoreCase("abc", null)  = false
    1027     * StringUtils.equalsIgnoreCase("abc", "abc") = true
    1028     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    1029     * </pre>
    1030     *
    1031     * @param str1  the first CharSequence, may be null
    1032     * @param str2  the second CharSequence, may be null
    1033     * @return {@code true} if the CharSequence are equal, case insensitive, or
    1034     *  both {@code null}
    1035     * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
    1036     */
    1037    public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) {
    1038        if (str1 == null || str2 == null) {
    1039            return str1 == str2;
    1040        } else if (str1 == str2) {
    1041            return true;
    1042        } else if (str1.length() != str2.length()) {
    1043            return false;
    1044        } else {
    1045            return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length());
    1046        }
    1047    }
    1048
    1049    // Compare
    1050    //-----------------------------------------------------------------------
    1051    /**
    1052     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
    1053     * <ul>
    1054     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    1055     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    1056     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    1057     * </ul>
    1058     *
    1059     * <p>This is a {@code null} safe version of :</p>
    1060     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    1061     *
    1062     * <p>{@code null} value is considered less than non-{@code null} value.
    1063     * Two {@code null} references are considered equal.</p>
    1064     *
    1065     * <pre>
    1066     * StringUtils.compare(null, null)   = 0
    1067     * StringUtils.compare(null , "a")   &lt; 0
    1068     * StringUtils.compare("a", null)    &gt; 0
    1069     * StringUtils.compare("abc", "abc") = 0
    1070     * StringUtils.compare("a", "b")     &lt; 0
    1071     * StringUtils.compare("b", "a")     &gt; 0
    1072     * StringUtils.compare("a", "B")     &gt; 0
    1073     * StringUtils.compare("ab", "abc")  &lt; 0
    1074     * </pre>
    1075     *
    1076     * @see #compare(String, String, boolean)
    1077     * @see String#compareTo(String)
    1078     * @param str1  the String to compare from
    1079     * @param str2  the String to compare to
    1080     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
    1081     * @since 3.5
    1082     */
    1083    public static int compare(final String str1, final String str2) {
    1084        return compare(str1, str2, true);
    1085    }
    1086
    1087    /**
    1088     * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
    1089     * <ul>
    1090     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    1091     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    1092     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    1093     * </ul>
    1094     *
    1095     * <p>This is a {@code null} safe version of :</p>
    1096     * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
    1097     *
    1098     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    1099     * Two {@code null} references are considered equal.</p>
    1100     *
    1101     * <pre>
    1102     * StringUtils.compare(null, null, *)     = 0
    1103     * StringUtils.compare(null , "a", true)  &lt; 0
    1104     * StringUtils.compare(null , "a", false) &gt; 0
    1105     * StringUtils.compare("a", null, true)   &gt; 0
    1106     * StringUtils.compare("a", null, false)  &lt; 0
    1107     * StringUtils.compare("abc", "abc", *)   = 0
    1108     * StringUtils.compare("a", "b", *)       &lt; 0
    1109     * StringUtils.compare("b", "a", *)       &gt; 0
    1110     * StringUtils.compare("a", "B", *)       &gt; 0
    1111     * StringUtils.compare("ab", "abc", *)    &lt; 0
    1112     * </pre>
    1113     *
    1114     * @see String#compareTo(String)
    1115     * @param str1  the String to compare from
    1116     * @param str2  the String to compare to
    1117     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    1118     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
    1119     * @since 3.5
    1120     */
    1121    public static int compare(final String str1, final String str2, final boolean nullIsLess) {
    1122        if (str1 == str2) {
    1123            return 0;
    1124        }
    1125        if (str1 == null) {
    1126            return nullIsLess ? -1 : 1;
    1127        }
    1128        if (str2 == null) {
    1129            return nullIsLess ? 1 : - 1;
    1130        }
    1131        return str1.compareTo(str2);
    1132    }
    1133
    1134    /**
    1135     * <p>Compare two Strings lexicographically, ignoring case differences,
    1136     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
    1137     * <ul>
    1138     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    1139     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    1140     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    1141     * </ul>
    1142     *
    1143     * <p>This is a {@code null} safe version of :</p>
    1144     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    1145     *
    1146     * <p>{@code null} value is considered less than non-{@code null} value.
    1147     * Two {@code null} references are considered equal.
    1148     * Comparison is case insensitive.</p>
    1149     *
    1150     * <pre>
    1151     * StringUtils.compareIgnoreCase(null, null)   = 0
    1152     * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
    1153     * StringUtils.compareIgnoreCase("a", null)    &gt; 0
    1154     * StringUtils.compareIgnoreCase("abc", "abc") = 0
    1155     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
    1156     * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
    1157     * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
    1158     * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
    1159     * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
    1160     * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
    1161     * </pre>
    1162     *
    1163     * @see #compareIgnoreCase(String, String, boolean)
    1164     * @see String#compareToIgnoreCase(String)
    1165     * @param str1  the String to compare from
    1166     * @param str2  the String to compare to
    1167     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    1168     *          ignoring case differences.
    1169     * @since 3.5
    1170     */
    1171    public static int compareIgnoreCase(final String str1, final String str2) {
    1172        return compareIgnoreCase(str1, str2, true);
    1173    }
    1174
    1175    /**
    1176     * <p>Compare two Strings lexicographically, ignoring case differences,
    1177     * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
    1178     * <ul>
    1179     *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
    1180     *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
    1181     *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
    1182     * </ul>
    1183     *
    1184     * <p>This is a {@code null} safe version of :</p>
    1185     * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
    1186     *
    1187     * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
    1188     * Two {@code null} references are considered equal.
    1189     * Comparison is case insensitive.</p>
    1190     *
    1191     * <pre>
    1192     * StringUtils.compareIgnoreCase(null, null, *)     = 0
    1193     * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
    1194     * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
    1195     * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
    1196     * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
    1197     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
    1198     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
    1199     * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
    1200     * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
    1201     * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
    1202     * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
    1203     * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
    1204     * </pre>
    1205     *
    1206     * @see String#compareToIgnoreCase(String)
    1207     * @param str1  the String to compare from
    1208     * @param str2  the String to compare to
    1209     * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
    1210     * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
    1211     *          ignoring case differences.
    1212     * @since 3.5
    1213     */
    1214    public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
    1215        if (str1 == str2) {
    1216            return 0;
    1217        }
    1218        if (str1 == null) {
    1219            return nullIsLess ? -1 : 1;
    1220        }
    1221        if (str2 == null) {
    1222            return nullIsLess ? 1 : - 1;
    1223        }
    1224        return str1.compareToIgnoreCase(str2);
    1225    }
    1226
    1227    /**
    1228     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
    1229     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p>
    1230     *
    1231     * <pre>
    1232     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
    1233     * StringUtils.equalsAny(null, null, null)    = true
    1234     * StringUtils.equalsAny(null, "abc", "def")  = false
    1235     * StringUtils.equalsAny("abc", null, "def")  = false
    1236     * StringUtils.equalsAny("abc", "abc", "def") = true
    1237     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
    1238     * </pre>
    1239     *
    1240     * @param string to compare, may be {@code null}.
    1241     * @param searchStrings a vararg of strings, may be {@code null}.
    1242     * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>;
    1243     * {@code false} if <code>searchStrings</code> is null or contains no matches.
    1244     * @since 3.5
    1245     */
    1246    public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
    1247        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1248            for (final CharSequence next : searchStrings) {
    1249                if (equals(string, next)) {
    1250                    return true;
    1251                }
    1252            }
    1253        }
    1254        return false;
    1255    }
    1256
    1257
    1258    /**
    1259     * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
    1260     * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p>
    1261     *
    1262     * <pre>
    1263     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
    1264     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
    1265     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
    1266     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
    1267     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
    1268     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
    1269     * </pre>
    1270     *
    1271     * @param string to compare, may be {@code null}.
    1272     * @param searchStrings a vararg of strings, may be {@code null}.
    1273     * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>;
    1274     * {@code false} if <code>searchStrings</code> is null or contains no matches.
    1275     * @since 3.5
    1276     */
    1277    public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
    1278        if (ArrayUtils.isNotEmpty(searchStrings)) {
    1279            for (final CharSequence next : searchStrings) {
    1280                if (equalsIgnoreCase(string, next)) {
    1281                    return true;
    1282                }
    1283            }
    1284        }
    1285        return false;
    1286    }
    1287
    1288    // IndexOf
    1289    //-----------------------------------------------------------------------
    1290    /**
    1291     * Returns the index within <code>seq</code> of the first occurrence of
    1292     * the specified character. If a character with value
    1293     * <code>searchChar</code> occurs in the character sequence represented by
    1294     * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode
    1295     * code units) of the first such occurrence is returned. For
    1296     * values of <code>searchChar</code> in the range from 0 to 0xFFFF
    1297     * (inclusive), this is the smallest value <i>k</i> such that:
    1298     * <blockquote><pre>
    1299     * this.charAt(<i>k</i>) == searchChar
    1300     * </pre></blockquote>
    1301     * is true. For other values of <code>searchChar</code>, it is the
    1302     * smallest value <i>k</i> such that:
    1303     * <blockquote><pre>
    1304     * this.codePointAt(<i>k</i>) == searchChar
    1305     * </pre></blockquote>
    1306     * is true. In either case, if no such character occurs in <code>seq</code>,
    1307     * then {@code INDEX_NOT_FOUND (-1)} is returned.
    1308     *
    1309     * <p>Furthermore, a {@code null} or empty ("") CharSequence will
    1310     * return {@code INDEX_NOT_FOUND (-1)}.</p>
    1311     *
    1312     * <pre>
    1313     * StringUtils.indexOf(null, *)         = -1
    1314     * StringUtils.indexOf("", *)           = -1
    1315     * StringUtils.indexOf("aabaabaa", 'a') = 0
    1316     * StringUtils.indexOf("aabaabaa", 'b') = 2
    1317     * </pre>
    1318     *
    1319     * @param seq  the CharSequence to check, may be null
    1320     * @param searchChar  the character to find
    1321     * @return the first index of the search character,
    1322     *  -1 if no match or {@code null} string input
    1323     * @since 2.0
    1324     * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
    1325     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
    1326     */
    1327    public static int indexOf(final CharSequence seq, final int searchChar) {
    1328        if (isEmpty(seq)) {
    1329            return INDEX_NOT_FOUND;
    1330        }
    1331        return CharSequenceUtils.indexOf(seq, searchChar, 0);
    1332    }
    1333
    1334    /**
    1335     *
    1336     * Returns the index within <code>seq</code> of the first occurrence of the
    1337     * specified character, starting the search at the specified index.
    1338     * <p>
    1339     * If a character with value <code>searchChar</code> occurs in the
    1340     * character sequence represented by the <code>seq</code> <code>CharSequence</code>
    1341     * object at an index no smaller than <code>startPos</code>, then
    1342     * the index of the first such occurrence is returned. For values
    1343     * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive),
    1344     * this is the smallest value <i>k</i> such that:
    1345     * <blockquote><pre>
    1346     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    1347     * </pre></blockquote>
    1348     * is true. For other values of <code>searchChar</code>, it is the
    1349     * smallest value <i>k</i> such that:
    1350     * <blockquote><pre>
    1351     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
    1352     * </pre></blockquote>
    1353     * is true. In either case, if no such character occurs in <code>seq</code>
    1354     * at or after position <code>startPos</code>, then
    1355     * <code>-1</code> is returned.
    1356     *
    1357     * <p>
    1358     * There is no restriction on the value of <code>startPos</code>. If it
    1359     * is negative, it has the same effect as if it were zero: this entire
    1360     * string may be searched. If it is greater than the length of this
    1361     * string, it has the same effect as if it were equal to the length of
    1362     * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
    1363     * {@code null} or empty ("") CharSequence will
    1364     * return {@code (INDEX_NOT_FOUND) -1}.
    1365     *
    1366     * <p>All indices are specified in <code>char</code> values
    1367     * (Unicode code units).
    1368     *
    1369     * <pre>
    1370     * StringUtils.indexOf(null, *, *)          = -1
    1371     * StringUtils.indexOf("", *, *)            = -1
    1372     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    1373     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    1374     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    1375     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    1376     * </pre>
    1377     *
    1378     * @param seq  the CharSequence to check, may be null
    1379     * @param searchChar  the character to find
    1380     * @param startPos  the start position, negative treated as zero
    1381     * @return the first index of the search character (always &ge; startPos),
    1382     *  -1 if no match or {@code null} string input
    1383     * @since 2.0
    1384     * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
    1385     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
    1386     */
    1387    public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
    1388        if (isEmpty(seq)) {
    1389            return INDEX_NOT_FOUND;
    1390        }
    1391        return CharSequenceUtils.indexOf(seq, searchChar, startPos);
    1392    }
    1393
    1394    /**
    1395     * <p>Finds the first index within a CharSequence, handling {@code null}.
    1396     * This method uses {@link String#indexOf(String, int)} if possible.</p>
    1397     *
    1398     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    1399     *
    1400     * <pre>
    1401     * StringUtils.indexOf(null, *)          = -1
    1402     * StringUtils.indexOf(*, null)          = -1
    1403     * StringUtils.indexOf("", "")           = 0
    1404     * StringUtils.indexOf("", *)            = -1 (except when * = "")
    1405     * StringUtils.indexOf("aabaabaa", "a")  = 0
    1406     * StringUtils.indexOf("aabaabaa", "b")  = 2
    1407     * StringUtils.indexOf("aabaabaa", "ab") = 1
    1408     * StringUtils.indexOf("aabaabaa", "")   = 0
    1409     * </pre>
    1410     *
    1411     * @param seq  the CharSequence to check, may be null
    1412     * @param searchSeq  the CharSequence to find, may be null
    1413     * @return the first index of the search CharSequence,
    1414     *  -1 if no match or {@code null} string input
    1415     * @since 2.0
    1416     * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
    1417     */
    1418    public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
    1419        if (seq == null || searchSeq == null) {
    1420            return INDEX_NOT_FOUND;
    1421        }
    1422        return CharSequenceUtils.indexOf(seq, searchSeq, 0);
    1423    }
    1424
    1425    /**
    1426     * <p>Finds the first index within a CharSequence, handling {@code null}.
    1427     * This method uses {@link String#indexOf(String, int)} if possible.</p>
    1428     *
    1429     * <p>A {@code null} CharSequence will return {@code -1}.
    1430     * A negative start position is treated as zero.
    1431     * An empty ("") search CharSequence always matches.
    1432     * A start position greater than the string length only matches
    1433     * an empty search CharSequence.</p>
    1434     *
    1435     * <pre>
    1436     * StringUtils.indexOf(null, *, *)          = -1
    1437     * StringUtils.indexOf(*, null, *)          = -1
    1438     * StringUtils.indexOf("", "", 0)           = 0
    1439     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    1440     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    1441     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    1442     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    1443     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    1444     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    1445     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    1446     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    1447     * StringUtils.indexOf("abc", "", 9)        = 3
    1448     * </pre>
    1449     *
    1450     * @param seq  the CharSequence to check, may be null
    1451     * @param searchSeq  the CharSequence to find, may be null
    1452     * @param startPos  the start position, negative treated as zero
    1453     * @return the first index of the search CharSequence (always &ge; startPos),
    1454     *  -1 if no match or {@code null} string input
    1455     * @since 2.0
    1456     * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
    1457     */
    1458    public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    1459        if (seq == null || searchSeq == null) {
    1460            return INDEX_NOT_FOUND;
    1461        }
    1462        return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
    1463    }
    1464
    1465    /**
    1466     * <p>Finds the n-th index within a CharSequence, handling {@code null}.
    1467     * This method uses {@link String#indexOf(String)} if possible.</p>
    1468     * <p><b>Note:</b> The code starts looking for a match at the start of the target,
    1469     * incrementing the starting index by one after each successful match
    1470     * (unless {@code searchStr} is an empty string in which case the position
    1471     * is never incremented and {@code 0} is returned immediately).
    1472     * This means that matches may overlap.</p>
    1473     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    1474     *
    1475     * <pre>
    1476     * StringUtils.ordinalIndexOf(null, *, *)          = -1
    1477     * StringUtils.ordinalIndexOf(*, null, *)          = -1
    1478     * StringUtils.ordinalIndexOf("", "", *)           = 0
    1479     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    1480     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    1481     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    1482     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    1483     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    1484     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    1485     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    1486     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    1487     * </pre>
    1488     *
    1489     * <p>Matches may overlap:</p>
    1490     * <pre>
    1491     * StringUtils.ordinalIndexOf("ababab","aba", 1)   = 0
    1492     * StringUtils.ordinalIndexOf("ababab","aba", 2)   = 2
    1493     * StringUtils.ordinalIndexOf("ababab","aba", 3)   = -1
    1494     *
    1495     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
    1496     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
    1497     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
    1498     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
    1499     * </pre>
    1500     *
    1501     * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
    1502     *
    1503     * <pre>
    1504     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    1505     * </pre>
    1506     *
    1507     * @param str  the CharSequence to check, may be null
    1508     * @param searchStr  the CharSequence to find, may be null
    1509     * @param ordinal  the n-th {@code searchStr} to find
    1510     * @return the n-th index of the search CharSequence,
    1511     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    1512     * @since 2.1
    1513     * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
    1514     */
    1515    public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    1516        return ordinalIndexOf(str, searchStr, ordinal, false);
    1517    }
    1518
    1519    /**
    1520     * <p>Finds the n-th index within a String, handling {@code null}.
    1521     * This method uses {@link String#indexOf(String)} if possible.</p>
    1522     * <p>Note that matches may overlap<p>
    1523     *
    1524     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    1525     *
    1526     * @param str  the CharSequence to check, may be null
    1527     * @param searchStr  the CharSequence to find, may be null
    1528     * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
    1529     * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
    1530     * @return the n-th index of the search CharSequence,
    1531     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    1532     */
    1533    // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
    1534    private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
    1535        if (str == null || searchStr == null || ordinal <= 0) {
    1536            return INDEX_NOT_FOUND;
    1537        }
    1538        if (searchStr.length() == 0) {
    1539            return lastIndex ? str.length() : 0;
    1540        }
    1541        int found = 0;
    1542        // set the initial index beyond the end of the string
    1543        // this is to allow for the initial index decrement/increment
    1544        int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    1545        do {
    1546            if (lastIndex) {
    1547                index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
    1548            } else {
    1549                index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
    1550            }
    1551            if (index < 0) {
    1552                return index;
    1553            }
    1554            found++;
    1555        } while (found < ordinal);
    1556        return index;
    1557    }
    1558
    1559    /**
    1560     * <p>Case in-sensitive find of the first index within a CharSequence.</p>
    1561     *
    1562     * <p>A {@code null} CharSequence will return {@code -1}.
    1563     * A negative start position is treated as zero.
    1564     * An empty ("") search CharSequence always matches.
    1565     * A start position greater than the string length only matches
    1566     * an empty search CharSequence.</p>
    1567     *
    1568     * <pre>
    1569     * StringUtils.indexOfIgnoreCase(null, *)          = -1
    1570     * StringUtils.indexOfIgnoreCase(*, null)          = -1
    1571     * StringUtils.indexOfIgnoreCase("", "")           = 0
    1572     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    1573     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    1574     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    1575     * </pre>
    1576     *
    1577     * @param str  the CharSequence to check, may be null
    1578     * @param searchStr  the CharSequence to find, may be null
    1579     * @return the first index of the search CharSequence,
    1580     *  -1 if no match or {@code null} string input
    1581     * @since 2.5
    1582     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
    1583     */
    1584    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1585        return indexOfIgnoreCase(str, searchStr, 0);
    1586    }
    1587
    1588    /**
    1589     * <p>Case in-sensitive find of the first index within a CharSequence
    1590     * from the specified position.</p>
    1591     *
    1592     * <p>A {@code null} CharSequence will return {@code -1}.
    1593     * A negative start position is treated as zero.
    1594     * An empty ("") search CharSequence always matches.
    1595     * A start position greater than the string length only matches
    1596     * an empty search CharSequence.</p>
    1597     *
    1598     * <pre>
    1599     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    1600     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    1601     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    1602     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    1603     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    1604     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    1605     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    1606     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    1607     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    1608     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    1609     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
    1610     * </pre>
    1611     *
    1612     * @param str  the CharSequence to check, may be null
    1613     * @param searchStr  the CharSequence to find, may be null
    1614     * @param startPos  the start position, negative treated as zero
    1615     * @return the first index of the search CharSequence (always &ge; startPos),
    1616     *  -1 if no match or {@code null} string input
    1617     * @since 2.5
    1618     * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
    1619     */
    1620    public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    1621        if (str == null || searchStr == null) {
    1622            return INDEX_NOT_FOUND;
    1623        }
    1624        if (startPos < 0) {
    1625            startPos = 0;
    1626        }
    1627        final int endLimit = str.length() - searchStr.length() + 1;
    1628        if (startPos > endLimit) {
    1629            return INDEX_NOT_FOUND;
    1630        }
    1631        if (searchStr.length() == 0) {
    1632            return startPos;
    1633        }
    1634        for (int i = startPos; i < endLimit; i++) {
    1635            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
    1636                return i;
    1637            }
    1638        }
    1639        return INDEX_NOT_FOUND;
    1640    }
    1641
    1642    // LastIndexOf
    1643    //-----------------------------------------------------------------------
    1644    /**
    1645     * Returns the index within <code>seq</code> of the last occurrence of
    1646     * the specified character. For values of <code>searchChar</code> in the
    1647     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
    1648     * units) returned is the largest value <i>k</i> such that:
    1649     * <blockquote><pre>
    1650     * this.charAt(<i>k</i>) == searchChar
    1651     * </pre></blockquote>
    1652     * is true. For other values of <code>searchChar</code>, it is the
    1653     * largest value <i>k</i> such that:
    1654     * <blockquote><pre>
    1655     * this.codePointAt(<i>k</i>) == searchChar
    1656     * </pre></blockquote>
    1657     * is true.  In either case, if no such character occurs in this
    1658     * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
    1659     * <code>CharSequence</code> will return {@code -1}. The
    1660     * <code>seq</code> <code>CharSequence</code> object is searched backwards
    1661     * starting at the last character.
    1662     *
    1663     * <pre>
    1664     * StringUtils.lastIndexOf(null, *)         = -1
    1665     * StringUtils.lastIndexOf("", *)           = -1
    1666     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    1667     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    1668     * </pre>
    1669     *
    1670     * @param seq  the <code>CharSequence</code> to check, may be null
    1671     * @param searchChar  the character to find
    1672     * @return the last index of the search character,
    1673     *  -1 if no match or {@code null} string input
    1674     * @since 2.0
    1675     * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
    1676     * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
    1677     */
    1678    public static int lastIndexOf(final CharSequence seq, final int searchChar) {
    1679        if (isEmpty(seq)) {
    1680            return INDEX_NOT_FOUND;
    1681        }
    1682        return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
    1683    }
    1684
    1685    /**
    1686     * Returns the index within <code>seq</code> of the last occurrence of
    1687     * the specified character, searching backward starting at the
    1688     * specified index. For values of <code>searchChar</code> in the range
    1689     * from 0 to 0xFFFF (inclusive), the index returned is the largest
    1690     * value <i>k</i> such that:
    1691     * <blockquote><pre>
    1692     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    1693     * </pre></blockquote>
    1694     * is true. For other values of <code>searchChar</code>, it is the
    1695     * largest value <i>k</i> such that:
    1696     * <blockquote><pre>
    1697     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
    1698     * </pre></blockquote>
    1699     * is true. In either case, if no such character occurs in <code>seq</code>
    1700     * at or before position <code>startPos</code>, then
    1701     * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
    1702     * <code>CharSequence</code> will return {@code -1}. A start position greater
    1703     * than the string length searches the whole string.
    1704     * The search starts at the <code>startPos</code> and works backwards;
    1705     * matches starting after the start position are ignored.
    1706     *
    1707     * <p>All indices are specified in <code>char</code> values
    1708     * (Unicode code units).
    1709     *
    1710     * <pre>
    1711     * StringUtils.lastIndexOf(null, *, *)          = -1
    1712     * StringUtils.lastIndexOf("", *,  *)           = -1
    1713     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    1714     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    1715     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    1716     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    1717     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    1718     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    1719     * </pre>
    1720     *
    1721     * @param seq  the CharSequence to check, may be null
    1722     * @param searchChar  the character to find
    1723     * @param startPos  the start position
    1724     * @return the last index of the search character (always &le; startPos),
    1725     *  -1 if no match or {@code null} string input
    1726     * @since 2.0
    1727     * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
    1728     */
    1729    public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
    1730        if (isEmpty(seq)) {
    1731            return INDEX_NOT_FOUND;
    1732        }
    1733        return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
    1734    }
    1735
    1736    /**
    1737     * <p>Finds the last index within a CharSequence, handling {@code null}.
    1738     * This method uses {@link String#lastIndexOf(String)} if possible.</p>
    1739     *
    1740     * <p>A {@code null} CharSequence will return {@code -1}.</p>
    1741     *
    1742     * <pre>
    1743     * StringUtils.lastIndexOf(null, *)          = -1
    1744     * StringUtils.lastIndexOf(*, null)          = -1
    1745     * StringUtils.lastIndexOf("", "")           = 0
    1746     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    1747     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    1748     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    1749     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    1750     * </pre>
    1751     *
    1752     * @param seq  the CharSequence to check, may be null
    1753     * @param searchSeq  the CharSequence to find, may be null
    1754     * @return the last index of the search String,
    1755     *  -1 if no match or {@code null} string input
    1756     * @since 2.0
    1757     * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
    1758     */
    1759    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
    1760        if (seq == null || searchSeq == null) {
    1761            return INDEX_NOT_FOUND;
    1762        }
    1763        return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
    1764    }
    1765
    1766    /**
    1767     * <p>Finds the n-th last index within a String, handling {@code null}.
    1768     * This method uses {@link String#lastIndexOf(String)}.</p>
    1769     *
    1770     * <p>A {@code null} String will return {@code -1}.</p>
    1771     *
    1772     * <pre>
    1773     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    1774     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    1775     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    1776     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    1777     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    1778     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    1779     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    1780     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    1781     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    1782     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    1783     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    1784     * </pre>
    1785     *
    1786     * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
    1787     *
    1788     * <pre>
    1789     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    1790     * </pre>
    1791     *
    1792     * @param str  the CharSequence to check, may be null
    1793     * @param searchStr  the CharSequence to find, may be null
    1794     * @param ordinal  the n-th last {@code searchStr} to find
    1795     * @return the n-th last index of the search CharSequence,
    1796     *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
    1797     * @since 2.5
    1798     * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
    1799     */
    1800    public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
    1801        return ordinalIndexOf(str, searchStr, ordinal, true);
    1802    }
    1803
    1804    /**
    1805     * <p>Finds the last index within a CharSequence, handling {@code null}.
    1806     * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
    1807     *
    1808     * <p>A {@code null} CharSequence will return {@code -1}.
    1809     * A negative start position returns {@code -1}.
    1810     * An empty ("") search CharSequence always matches unless the start position is negative.
    1811     * A start position greater than the string length searches the whole string.
    1812     * The search starts at the startPos and works backwards; matches starting after the start
    1813     * position are ignored.
    1814     * </p>
    1815     *
    1816     * <pre>
    1817     * StringUtils.lastIndexOf(null, *, *)          = -1
    1818     * StringUtils.lastIndexOf(*, null, *)          = -1
    1819     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    1820     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    1821     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    1822     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    1823     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    1824     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    1825     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    1826     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
    1827     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
    1828     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
    1829     * </pre>
    1830     *
    1831     * @param seq  the CharSequence to check, may be null
    1832     * @param searchSeq  the CharSequence to find, may be null
    1833     * @param startPos  the start position, negative treated as zero
    1834     * @return the last index of the search CharSequence (always &le; startPos),
    1835     *  -1 if no match or {@code null} string input
    1836     * @since 2.0
    1837     * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
    1838     */
    1839    public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
    1840        if (seq == null || searchSeq == null) {
    1841            return INDEX_NOT_FOUND;
    1842        }
    1843        return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
    1844    }
    1845
    1846    /**
    1847     * <p>Case in-sensitive find of the last index within a CharSequence.</p>
    1848     *
    1849     * <p>A {@code null} CharSequence will return {@code -1}.
    1850     * A negative start position returns {@code -1}.
    1851     * An empty ("") search CharSequence always matches unless the start position is negative.
    1852     * A start position greater than the string length searches the whole string.</p>
    1853     *
    1854     * <pre>
    1855     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    1856     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    1857     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    1858     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    1859     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    1860     * </pre>
    1861     *
    1862     * @param str  the CharSequence to check, may be null
    1863     * @param searchStr  the CharSequence to find, may be null
    1864     * @return the first index of the search CharSequence,
    1865     *  -1 if no match or {@code null} string input
    1866     * @since 2.5
    1867     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
    1868     */
    1869    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    1870        if (str == null || searchStr == null) {
    1871            return INDEX_NOT_FOUND;
    1872        }
    1873        return lastIndexOfIgnoreCase(str, searchStr, str.length());
    1874    }
    1875
    1876    /**
    1877     * <p>Case in-sensitive find of the last index within a CharSequence
    1878     * from the specified position.</p>
    1879     *
    1880     * <p>A {@code null} CharSequence will return {@code -1}.
    1881     * A negative start position returns {@code -1}.
    1882     * An empty ("") search CharSequence always matches unless the start position is negative.
    1883     * A start position greater than the string length searches the whole string.
    1884     * The search starts at the startPos and works backwards; matches starting after the start
    1885     * position are ignored.
    1886     * </p>
    1887     *
    1888     * <pre>
    1889     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    1890     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    1891     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    1892     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    1893     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    1894     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    1895     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    1896     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    1897     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    1898     * </pre>
    1899     *
    1900     * @param str  the CharSequence to check, may be null
    1901     * @param searchStr  the CharSequence to find, may be null
    1902     * @param startPos  the start position
    1903     * @return the last index of the search CharSequence (always &le; startPos),
    1904     *  -1 if no match or {@code null} input
    1905     * @since 2.5
    1906     * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
    1907     */
    1908    public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
    1909        if (str == null || searchStr == null) {
    1910            return INDEX_NOT_FOUND;
    1911        }
    1912        if (startPos > str.length() - searchStr.length()) {
    1913            startPos = str.length() - searchStr.length();
    1914        }
    1915        if (startPos < 0) {
    1916            return INDEX_NOT_FOUND;
    1917        }
    1918        if (searchStr.length() == 0) {
    1919            return startPos;
    1920        }
    1921
    1922        for (int i = startPos; i >= 0; i--) {
    1923            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
    1924                return i;
    1925            }
    1926        }
    1927        return INDEX_NOT_FOUND;
    1928    }
    1929
    1930    // Contains
    1931    //-----------------------------------------------------------------------
    1932    /**
    1933     * <p>Checks if CharSequence contains a search character, handling {@code null}.
    1934     * This method uses {@link String#indexOf(int)} if possible.</p>
    1935     *
    1936     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
    1937     *
    1938     * <pre>
    1939     * StringUtils.contains(null, *)    = false
    1940     * StringUtils.contains("", *)      = false
    1941     * StringUtils.contains("abc", 'a') = true
    1942     * StringUtils.contains("abc", 'z') = false
    1943     * </pre>
    1944     *
    1945     * @param seq  the CharSequence to check, may be null
    1946     * @param searchChar  the character to find
    1947     * @return true if the CharSequence contains the search character,
    1948     *  false if not or {@code null} string input
    1949     * @since 2.0
    1950     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
    1951     */
    1952    public static boolean contains(final CharSequence seq, final int searchChar) {
    1953        if (isEmpty(seq)) {
    1954            return false;
    1955        }
    1956        return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
    1957    }
    1958
    1959    /**
    1960     * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
    1961     * This method uses {@link String#indexOf(String)} if possible.</p>
    1962     *
    1963     * <p>A {@code null} CharSequence will return {@code false}.</p>
    1964     *
    1965     * <pre>
    1966     * StringUtils.contains(null, *)     = false
    1967     * StringUtils.contains(*, null)     = false
    1968     * StringUtils.contains("", "")      = true
    1969     * StringUtils.contains("abc", "")   = true
    1970     * StringUtils.contains("abc", "a")  = true
    1971     * StringUtils.contains("abc", "z")  = false
    1972     * </pre>
    1973     *
    1974     * @param seq  the CharSequence to check, may be null
    1975     * @param searchSeq  the CharSequence to find, may be null
    1976     * @return true if the CharSequence contains the search CharSequence,
    1977     *  false if not or {@code null} string input
    1978     * @since 2.0
    1979     * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
    1980     */
    1981    public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
    1982        if (seq == null || searchSeq == null) {
    1983            return false;
    1984        }
    1985        return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
    1986    }
    1987
    1988    /**
    1989     * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
    1990     * handling {@code null}. Case-insensitivity is defined as by
    1991     * {@link String#equalsIgnoreCase(String)}.
    1992     *
    1993     * <p>A {@code null} CharSequence will return {@code false}.</p>
    1994     *
    1995     * <pre>
    1996     * StringUtils.containsIgnoreCase(null, *) = false
    1997     * StringUtils.containsIgnoreCase(*, null) = false
    1998     * StringUtils.containsIgnoreCase("", "") = true
    1999     * StringUtils.containsIgnoreCase("abc", "") = true
    2000     * StringUtils.containsIgnoreCase("abc", "a") = true
    2001     * StringUtils.containsIgnoreCase("abc", "z") = false
    2002     * StringUtils.containsIgnoreCase("abc", "A") = true
    2003     * StringUtils.containsIgnoreCase("abc", "Z") = false
    2004     * </pre>
    2005     *
    2006     * @param str  the CharSequence to check, may be null
    2007     * @param searchStr  the CharSequence to find, may be null
    2008     * @return true if the CharSequence contains the search CharSequence irrespective of
    2009     * case or false if not or {@code null} string input
    2010     * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
    2011     */
    2012    public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
    2013        if (str == null || searchStr == null) {
    2014            return false;
    2015        }
    2016        final int len = searchStr.length();
    2017        final int max = str.length() - len;
    2018        for (int i = 0; i <= max; i++) {
    2019            if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
    2020                return true;
    2021            }
    2022        }
    2023        return false;
    2024    }
    2025
    2026    /**
    2027     * <p>Check whether the given CharSequence contains any whitespace characters.</p>
    2028     *
    2029     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    2030     *
    2031     * @param seq the CharSequence to check (may be {@code null})
    2032     * @return {@code true} if the CharSequence is not empty and
    2033     * contains at least 1 (breaking) whitespace character
    2034     * @since 3.0
    2035     */
    2036    // From org.springframework.util.StringUtils, under Apache License 2.0
    2037    public static boolean containsWhitespace(final CharSequence seq) {
    2038        if (isEmpty(seq)) {
    2039            return false;
    2040        }
    2041        final int strLen = seq.length();
    2042        for (int i = 0; i < strLen; i++) {
    2043            if (Character.isWhitespace(seq.charAt(i))) {
    2044                return true;
    2045            }
    2046        }
    2047        return false;
    2048    }
    2049
    2050    // IndexOfAny chars
    2051    //-----------------------------------------------------------------------
    2052    /**
    2053     * <p>Search a CharSequence to find the first index of any
    2054     * character in the given set of characters.</p>
    2055     *
    2056     * <p>A {@code null} String will return {@code -1}.
    2057     * A {@code null} or zero length search array will return {@code -1}.</p>
    2058     *
    2059     * <pre>
    2060     * StringUtils.indexOfAny(null, *)                = -1
    2061     * StringUtils.indexOfAny("", *)                  = -1
    2062     * StringUtils.indexOfAny(*, null)                = -1
    2063     * StringUtils.indexOfAny(*, [])                  = -1
    2064     * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
    2065     * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
    2066     * StringUtils.indexOfAny("aba", ['z'])           = -1
    2067     * </pre>
    2068     *
    2069     * @param cs  the CharSequence to check, may be null
    2070     * @param searchChars  the chars to search for, may be null
    2071     * @return the index of any of the chars, -1 if no match or null input
    2072     * @since 2.0
    2073     * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
    2074     */
    2075    public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    2076        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2077            return INDEX_NOT_FOUND;
    2078        }
    2079        final int csLen = cs.length();
    2080        final int csLast = csLen - 1;
    2081        final int searchLen = searchChars.length;
    2082        final int searchLast = searchLen - 1;
    2083        for (int i = 0; i < csLen; i++) {
    2084            final char ch = cs.charAt(i);
    2085            for (int j = 0; j < searchLen; j++) {
    2086                if (searchChars[j] == ch) {
    2087                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
    2088                        // ch is a supplementary character
    2089                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2090                            return i;
    2091                        }
    2092                    } else {
    2093                        return i;
    2094                    }
    2095                }
    2096            }
    2097        }
    2098        return INDEX_NOT_FOUND;
    2099    }
    2100
    2101    /**
    2102     * <p>Search a CharSequence to find the first index of any
    2103     * character in the given set of characters.</p>
    2104     *
    2105     * <p>A {@code null} String will return {@code -1}.
    2106     * A {@code null} search string will return {@code -1}.</p>
    2107     *
    2108     * <pre>
    2109     * StringUtils.indexOfAny(null, *)            = -1
    2110     * StringUtils.indexOfAny("", *)              = -1
    2111     * StringUtils.indexOfAny(*, null)            = -1
    2112     * StringUtils.indexOfAny(*, "")              = -1
    2113     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    2114     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    2115     * StringUtils.indexOfAny("aba","z")          = -1
    2116     * </pre>
    2117     *
    2118     * @param cs  the CharSequence to check, may be null
    2119     * @param searchChars  the chars to search for, may be null
    2120     * @return the index of any of the chars, -1 if no match or null input
    2121     * @since 2.0
    2122     * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    2123     */
    2124    public static int indexOfAny(final CharSequence cs, final String searchChars) {
    2125        if (isEmpty(cs) || isEmpty(searchChars)) {
    2126            return INDEX_NOT_FOUND;
    2127        }
    2128        return indexOfAny(cs, searchChars.toCharArray());
    2129    }
    2130
    2131    // ContainsAny
    2132    //-----------------------------------------------------------------------
    2133    /**
    2134     * <p>Checks if the CharSequence contains any character in the given
    2135     * set of characters.</p>
    2136     *
    2137     * <p>A {@code null} CharSequence will return {@code false}.
    2138     * A {@code null} or zero length search array will return {@code false}.</p>
    2139     *
    2140     * <pre>
    2141     * StringUtils.containsAny(null, *)                = false
    2142     * StringUtils.containsAny("", *)                  = false
    2143     * StringUtils.containsAny(*, null)                = false
    2144     * StringUtils.containsAny(*, [])                  = false
    2145     * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
    2146     * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
    2147     * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
    2148     * StringUtils.containsAny("aba", ['z'])           = false
    2149     * </pre>
    2150     *
    2151     * @param cs  the CharSequence to check, may be null
    2152     * @param searchChars  the chars to search for, may be null
    2153     * @return the {@code true} if any of the chars are found,
    2154     * {@code false} if no match or null input
    2155     * @since 2.4
    2156     * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
    2157     */
    2158    public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    2159        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2160            return false;
    2161        }
    2162        final int csLength = cs.length();
    2163        final int searchLength = searchChars.length;
    2164        final int csLast = csLength - 1;
    2165        final int searchLast = searchLength - 1;
    2166        for (int i = 0; i < csLength; i++) {
    2167            final char ch = cs.charAt(i);
    2168            for (int j = 0; j < searchLength; j++) {
    2169                if (searchChars[j] == ch) {
    2170                    if (Character.isHighSurrogate(ch)) {
    2171                        if (j == searchLast) {
    2172                            // missing low surrogate, fine, like String.indexOf(String)
    2173                            return true;
    2174                        }
    2175                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    2176                            return true;
    2177                        }
    2178                    } else {
    2179                        // ch is in the Basic Multilingual Plane
    2180                        return true;
    2181                    }
    2182                }
    2183            }
    2184        }
    2185        return false;
    2186    }
    2187
    2188    /**
    2189     * <p>
    2190     * Checks if the CharSequence contains any character in the given set of characters.
    2191     * </p>
    2192     *
    2193     * <p>
    2194     * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
    2195     * {@code false}.
    2196     * </p>
    2197     *
    2198     * <pre>
    2199     * StringUtils.containsAny(null, *)               = false
    2200     * StringUtils.containsAny("", *)                 = false
    2201     * StringUtils.containsAny(*, null)               = false
    2202     * StringUtils.containsAny(*, "")                 = false
    2203     * StringUtils.containsAny("zzabyycdxx", "za")    = true
    2204     * StringUtils.containsAny("zzabyycdxx", "by")    = true
    2205     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
    2206     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
    2207     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
    2208     * StringUtils.containsAny("aba","z")             = false
    2209     * </pre>
    2210     *
    2211     * @param cs
    2212     *            the CharSequence to check, may be null
    2213     * @param searchChars
    2214     *            the chars to search for, may be null
    2215     * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
    2216     * @since 2.4
    2217     * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
    2218     */
    2219    public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
    2220        if (searchChars == null) {
    2221            return false;
    2222        }
    2223        return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
    2224    }
    2225
    2226    /**
    2227     * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
    2228     *
    2229     * <p>
    2230     * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
    2231     * length search array will return {@code false}.
    2232     * </p>
    2233     *
    2234     * <pre>
    2235     * StringUtils.containsAny(null, *)            = false
    2236     * StringUtils.containsAny("", *)              = false
    2237     * StringUtils.containsAny(*, null)            = false
    2238     * StringUtils.containsAny(*, [])              = false
    2239     * StringUtils.containsAny("abcd", "ab", null) = true
    2240     * StringUtils.containsAny("abcd", "ab", "cd") = true
    2241     * StringUtils.containsAny("abc", "d", "abc")  = true
    2242     * </pre>
    2243     *
    2244     *
    2245     * @param cs The CharSequence to check, may be null
    2246     * @param searchCharSequences The array of CharSequences to search for, may be null.
    2247     * Individual CharSequences may be null as well.
    2248     * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
    2249     * @since 3.4
    2250     */
    2251    public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
    2252        if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
    2253            return false;
    2254        }
    2255        for (final CharSequence searchCharSequence : searchCharSequences) {
    2256            if (contains(cs, searchCharSequence)) {
    2257                return true;
    2258            }
    2259        }
    2260        return false;
    2261    }
    2262
    2263    // IndexOfAnyBut chars
    2264    //-----------------------------------------------------------------------
    2265    /**
    2266     * <p>Searches a CharSequence to find the first index of any
    2267     * character not in the given set of characters.</p>
    2268     *
    2269     * <p>A {@code null} CharSequence will return {@code -1}.
    2270     * A {@code null} or zero length search array will return {@code -1}.</p>
    2271     *
    2272     * <pre>
    2273     * StringUtils.indexOfAnyBut(null, *)                              = -1
    2274     * StringUtils.indexOfAnyBut("", *)                                = -1
    2275     * StringUtils.indexOfAnyBut(*, null)                              = -1
    2276     * StringUtils.indexOfAnyBut(*, [])                                = -1
    2277     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
    2278     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
    2279     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
    2280
    2281     * </pre>
    2282     *
    2283     * @param cs  the CharSequence to check, may be null
    2284     * @param searchChars  the chars to search for, may be null
    2285     * @return the index of any of the chars, -1 if no match or null input
    2286     * @since 2.0
    2287     * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
    2288     */
    2289    public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    2290        if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    2291            return INDEX_NOT_FOUND;
    2292        }
    2293        final int csLen = cs.length();
    2294        final int csLast = csLen - 1;
    2295        final int searchLen = searchChars.length;
    2296        final int searchLast = searchLen - 1;
    2297        outer:
    2298        for (int i = 0; i < csLen; i++) {
    2299            final char ch = cs.charAt(i);
    2300            for (int j = 0; j < searchLen; j++) {
    2301                if (searchChars[j] == ch) {
    2302                    if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
    2303                        if (searchChars[j + 1] == cs.charAt(i + 1)) {
    2304                            continue outer;
    2305                        }
    2306                    } else {
    2307                        continue outer;
    2308                    }
    2309                }
    2310            }
    2311            return i;
    2312        }
    2313        return INDEX_NOT_FOUND;
    2314    }
    2315
    2316    /**
    2317     * <p>Search a CharSequence to find the first index of any
    2318     * character not in the given set of characters.</p>
    2319     *
    2320     * <p>A {@code null} CharSequence will return {@code -1}.
    2321     * A {@code null} or empty search string will return {@code -1}.</p>
    2322     *
    2323     * <pre>
    2324     * StringUtils.indexOfAnyBut(null, *)            = -1
    2325     * StringUtils.indexOfAnyBut("", *)              = -1
    2326     * StringUtils.indexOfAnyBut(*, null)            = -1
    2327     * StringUtils.indexOfAnyBut(*, "")              = -1
    2328     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    2329     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
    2330     * StringUtils.indexOfAnyBut("aba","ab")         = -1
    2331     * </pre>
    2332     *
    2333     * @param seq  the CharSequence to check, may be null
    2334     * @param searchChars  the chars to search for, may be null
    2335     * @return the index of any of the chars, -1 if no match or null input
    2336     * @since 2.0
    2337     * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
    2338     */
    2339    public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
    2340        if (isEmpty(seq) || isEmpty(searchChars)) {
    2341            return INDEX_NOT_FOUND;
    2342        }
    2343        final int strLen = seq.length();
    2344        for (int i = 0; i < strLen; i++) {
    2345            final char ch = seq.charAt(i);
    2346            final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
    2347            if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
    2348                final char ch2 = seq.charAt(i + 1);
    2349                if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
    2350                    return i;
    2351                }
    2352            } else {
    2353                if (!chFound) {
    2354                    return i;
    2355                }
    2356            }
    2357        }
    2358        return INDEX_NOT_FOUND;
    2359    }
    2360
    2361    // ContainsOnly
    2362    //-----------------------------------------------------------------------
    2363    /**
    2364     * <p>Checks if the CharSequence contains only certain characters.</p>
    2365     *
    2366     * <p>A {@code null} CharSequence will return {@code false}.
    2367     * A {@code null} valid character array will return {@code false}.
    2368     * An empty CharSequence (length()=0) always returns {@code true}.</p>
    2369     *
    2370     * <pre>
    2371     * StringUtils.containsOnly(null, *)       = false
    2372     * StringUtils.containsOnly(*, null)       = false
    2373     * StringUtils.containsOnly("", *)         = true
    2374     * StringUtils.containsOnly("ab", '')      = false
    2375     * StringUtils.containsOnly("abab", 'abc') = true
    2376     * StringUtils.containsOnly("ab1", 'abc')  = false
    2377     * StringUtils.containsOnly("abz", 'abc')  = false
    2378     * </pre>
    2379     *
    2380     * @param cs  the String to check, may be null
    2381     * @param valid  an array of valid chars, may be null
    2382     * @return true if it only contains valid chars and is non-null
    2383     * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
    2384     */
    2385    public static boolean containsOnly(final CharSequence cs, final char... valid) {
    2386        // All these pre-checks are to maintain API with an older version
    2387        if (valid == null || cs == null) {
    2388            return false;
    2389        }
    2390        if (cs.length() == 0) {
    2391            return true;
    2392        }
    2393        if (valid.length == 0) {
    2394            return false;
    2395        }
    2396        return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    2397    }
    2398
    2399    /**
    2400     * <p>Checks if the CharSequence contains only certain characters.</p>
    2401     *
    2402     * <p>A {@code null} CharSequence will return {@code false}.
    2403     * A {@code null} valid character String will return {@code false}.
    2404     * An empty String (length()=0) always returns {@code true}.</p>
    2405     *
    2406     * <pre>
    2407     * StringUtils.containsOnly(null, *)       = false
    2408     * StringUtils.containsOnly(*, null)       = false
    2409     * StringUtils.containsOnly("", *)         = true
    2410     * StringUtils.containsOnly("ab", "")      = false
    2411     * StringUtils.containsOnly("abab", "abc") = true
    2412     * StringUtils.containsOnly("ab1", "abc")  = false
    2413     * StringUtils.containsOnly("abz", "abc")  = false
    2414     * </pre>
    2415     *
    2416     * @param cs  the CharSequence to check, may be null
    2417     * @param validChars  a String of valid chars, may be null
    2418     * @return true if it only contains valid chars and is non-null
    2419     * @since 2.0
    2420     * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    2421     */
    2422    public static boolean containsOnly(final CharSequence cs, final String validChars) {
    2423        if (cs == null || validChars == null) {
    2424            return false;
    2425        }
    2426        return containsOnly(cs, validChars.toCharArray());
    2427    }
    2428
    2429    // ContainsNone
    2430    //-----------------------------------------------------------------------
    2431    /**
    2432     * <p>Checks that the CharSequence does not contain certain characters.</p>
    2433     *
    2434     * <p>A {@code null} CharSequence will return {@code true}.
    2435     * A {@code null} invalid character array will return {@code true}.
    2436     * An empty CharSequence (length()=0) always returns true.</p>
    2437     *
    2438     * <pre>
    2439     * StringUtils.containsNone(null, *)       = true
    2440     * StringUtils.containsNone(*, null)       = true
    2441     * StringUtils.containsNone("", *)         = true
    2442     * StringUtils.containsNone("ab", '')      = true
    2443     * StringUtils.containsNone("abab", 'xyz') = true
    2444     * StringUtils.containsNone("ab1", 'xyz')  = true
    2445     * StringUtils.containsNone("abz", 'xyz')  = false
    2446     * </pre>
    2447     *
    2448     * @param cs  the CharSequence to check, may be null
    2449     * @param searchChars  an array of invalid chars, may be null
    2450     * @return true if it contains none of the invalid chars, or is null
    2451     * @since 2.0
    2452     * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
    2453     */
    2454    public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    2455        if (cs == null || searchChars == null) {
    2456            return true;
    2457        }
    2458        final int csLen = cs.length();
    2459        final int csLast = csLen - 1;
    2460        final int searchLen = searchChars.length;
    2461        final int searchLast = searchLen - 1;
    2462        for (int i = 0; i < csLen; i++) {
    2463            final char ch = cs.charAt(i);
    2464            for (int j = 0; j < searchLen; j++) {
    2465                if (searchChars[j] == ch) {
    2466                    if (Character.isHighSurrogate(ch)) {
    2467                        if (j == searchLast) {
    2468                            // missing low surrogate, fine, like String.indexOf(String)
    2469                            return false;
    2470                        }
    2471                        if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    2472                            return false;
    2473                        }
    2474                    } else {
    2475                        // ch is in the Basic Multilingual Plane
    2476                        return false;
    2477                    }
    2478                }
    2479            }
    2480        }
    2481        return true;
    2482    }
    2483
    2484    /**
    2485     * <p>Checks that the CharSequence does not contain certain characters.</p>
    2486     *
    2487     * <p>A {@code null} CharSequence will return {@code true}.
    2488     * A {@code null} invalid character array will return {@code true}.
    2489     * An empty String ("") always returns true.</p>
    2490     *
    2491     * <pre>
    2492     * StringUtils.containsNone(null, *)       = true
    2493     * StringUtils.containsNone(*, null)       = true
    2494     * StringUtils.containsNone("", *)         = true
    2495     * StringUtils.containsNone("ab", "")      = true
    2496     * StringUtils.containsNone("abab", "xyz") = true
    2497     * StringUtils.containsNone("ab1", "xyz")  = true
    2498     * StringUtils.containsNone("abz", "xyz")  = false
    2499     * </pre>
    2500     *
    2501     * @param cs  the CharSequence to check, may be null
    2502     * @param invalidChars  a String of invalid chars, may be null
    2503     * @return true if it contains none of the invalid chars, or is null
    2504     * @since 2.0
    2505     * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    2506     */
    2507    public static boolean containsNone(final CharSequence cs, final String invalidChars) {
    2508        if (cs == null || invalidChars == null) {
    2509            return true;
    2510        }
    2511        return containsNone(cs, invalidChars.toCharArray());
    2512    }
    2513
    2514    // IndexOfAny strings
    2515    //-----------------------------------------------------------------------
    2516    /**
    2517     * <p>Find the first index of any of a set of potential substrings.</p>
    2518     *
    2519     * <p>A {@code null} CharSequence will return {@code -1}.
    2520     * A {@code null} or zero length search array will return {@code -1}.
    2521     * A {@code null} search array entry will be ignored, but a search
    2522     * array containing "" will return {@code 0} if {@code str} is not
    2523     * null. This method uses {@link String#indexOf(String)} if possible.</p>
    2524     *
    2525     * <pre>
    2526     * StringUtils.indexOfAny(null, *)                     = -1
    2527     * StringUtils.indexOfAny(*, null)                     = -1
    2528     * StringUtils.indexOfAny(*, [])                       = -1
    2529     * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"])   = 2
    2530     * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"])   = 2
    2531     * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"])   = -1
    2532     * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
    2533     * StringUtils.indexOfAny("zzabyycdxx", [""])          = 0
    2534     * StringUtils.indexOfAny("", [""])                    = 0
    2535     * StringUtils.indexOfAny("", ["a"])                   = -1
    2536     * </pre>
    2537     *
    2538     * @param str  the CharSequence to check, may be null
    2539     * @param searchStrs  the CharSequences to search for, may be null
    2540     * @return the first index of any of the searchStrs in str, -1 if no match
    2541     * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
    2542     */
    2543    public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2544        if (str == null || searchStrs == null) {
    2545            return INDEX_NOT_FOUND;
    2546        }
    2547
    2548        // String's can't have a MAX_VALUEth index.
    2549        int ret = Integer.MAX_VALUE;
    2550
    2551        int tmp = 0;
    2552        for (final CharSequence search : searchStrs) {
    2553            if (search == null) {
    2554                continue;
    2555            }
    2556            tmp = CharSequenceUtils.indexOf(str, search, 0);
    2557            if (tmp == INDEX_NOT_FOUND) {
    2558                continue;
    2559            }
    2560
    2561            if (tmp < ret) {
    2562                ret = tmp;
    2563            }
    2564        }
    2565
    2566        return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
    2567    }
    2568
    2569    /**
    2570     * <p>Find the latest index of any of a set of potential substrings.</p>
    2571     *
    2572     * <p>A {@code null} CharSequence will return {@code -1}.
    2573     * A {@code null} search array will return {@code -1}.
    2574     * A {@code null} or zero length search array entry will be ignored,
    2575     * but a search array containing "" will return the length of {@code str}
    2576     * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
    2577     *
    2578     * <pre>
    2579     * StringUtils.lastIndexOfAny(null, *)                   = -1
    2580     * StringUtils.lastIndexOfAny(*, null)                   = -1
    2581     * StringUtils.lastIndexOfAny(*, [])                     = -1
    2582     * StringUtils.lastIndexOfAny(*, [null])                 = -1
    2583     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
    2584     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
    2585     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
    2586     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
    2587     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""])   = 10
    2588     * </pre>
    2589     *
    2590     * @param str  the CharSequence to check, may be null
    2591     * @param searchStrs  the CharSequences to search for, may be null
    2592     * @return the last index of any of the CharSequences, -1 if no match
    2593     * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
    2594     */
    2595    public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
    2596        if (str == null || searchStrs == null) {
    2597            return INDEX_NOT_FOUND;
    2598        }
    2599        int ret = INDEX_NOT_FOUND;
    2600        int tmp = 0;
    2601        for (final CharSequence search : searchStrs) {
    2602            if (search == null) {
    2603                continue;
    2604            }
    2605            tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
    2606            if (tmp > ret) {
    2607                ret = tmp;
    2608            }
    2609        }
    2610        return ret;
    2611    }
    2612
    2613    // Substring
    2614    //-----------------------------------------------------------------------
    2615    /**
    2616     * <p>Gets a substring from the specified String avoiding exceptions.</p>
    2617     *
    2618     * <p>A negative start position can be used to start {@code n}
    2619     * characters from the end of the String.</p>
    2620     *
    2621     * <p>A {@code null} String will return {@code null}.
    2622     * An empty ("") String will return "".</p>
    2623     *
    2624     * <pre>
    2625     * StringUtils.substring(null, *)   = null
    2626     * StringUtils.substring("", *)     = ""
    2627     * StringUtils.substring("abc", 0)  = "abc"
    2628     * StringUtils.substring("abc", 2)  = "c"
    2629     * StringUtils.substring("abc", 4)  = ""
    2630     * StringUtils.substring("abc", -2) = "bc"
    2631     * StringUtils.substring("abc", -4) = "abc"
    2632     * </pre>
    2633     *
    2634     * @param str  the String to get the substring from, may be null
    2635     * @param start  the position to start from, negative means
    2636     *  count back from the end of the String by this many characters
    2637     * @return substring from start position, {@code null} if null String input
    2638     */
    2639    public static String substring(final String str, int start) {
    2640        if (str == null) {
    2641            return null;
    2642        }
    2643
    2644        // handle negatives, which means last n characters
    2645        if (start < 0) {
    2646            start = str.length() + start; // remember start is negative
    2647        }
    2648
    2649        if (start < 0) {
    2650            start = 0;
    2651        }
    2652        if (start > str.length()) {
    2653            return EMPTY;
    2654        }
    2655
    2656        return str.substring(start);
    2657    }
    2658
    2659    /**
    2660     * <p>Gets a substring from the specified String avoiding exceptions.</p>
    2661     *
    2662     * <p>A negative start position can be used to start/end {@code n}
    2663     * characters from the end of the String.</p>
    2664     *
    2665     * <p>The returned substring starts with the character in the {@code start}
    2666     * position and ends before the {@code end} position. All position counting is
    2667     * zero-based -- i.e., to start at the beginning of the string use
    2668     * {@code start = 0}. Negative start and end positions can be used to
    2669     * specify offsets relative to the end of the String.</p>
    2670     *
    2671     * <p>If {@code start} is not strictly to the left of {@code end}, ""
    2672     * is returned.</p>
    2673     *
    2674     * <pre>
    2675     * StringUtils.substring(null, *, *)    = null
    2676     * StringUtils.substring("", * ,  *)    = "";
    2677     * StringUtils.substring("abc", 0, 2)   = "ab"
    2678     * StringUtils.substring("abc", 2, 0)   = ""
    2679     * StringUtils.substring("abc", 2, 4)   = "c"
    2680     * StringUtils.substring("abc", 4, 6)   = ""
    2681     * StringUtils.substring("abc", 2, 2)   = ""
    2682     * StringUtils.substring("abc", -2, -1) = "b"
    2683     * StringUtils.substring("abc", -4, 2)  = "ab"
    2684     * </pre>
    2685     *
    2686     * @param str  the String to get the substring from, may be null
    2687     * @param start  the position to start from, negative means
    2688     *  count back from the end of the String by this many characters
    2689     * @param end  the position to end at (exclusive), negative means
    2690     *  count back from the end of the String by this many characters
    2691     * @return substring from start position to end position,
    2692     *  {@code null} if null String input
    2693     */
    2694    public static String substring(final String str, int start, int end) {
    2695        if (str == null) {
    2696            return null;
    2697        }
    2698
    2699        // handle negatives
    2700        if (end < 0) {
    2701            end = str.length() + end; // remember end is negative
    2702        }
    2703        if (start < 0) {
    2704            start = str.length() + start; // remember start is negative
    2705        }
    2706
    2707        // check length next
    2708        if (end > str.length()) {
    2709            end = str.length();
    2710        }
    2711
    2712        // if start is greater than end, return ""
    2713        if (start > end) {
    2714            return EMPTY;
    2715        }
    2716
    2717        if (start < 0) {
    2718            start = 0;
    2719        }
    2720        if (end < 0) {
    2721            end = 0;
    2722        }
    2723
    2724        return str.substring(start, end);
    2725    }
    2726
    2727    // Left/Right/Mid
    2728    //-----------------------------------------------------------------------
    2729    /**
    2730     * <p>Gets the leftmost {@code len} characters of a String.</p>
    2731     *
    2732     * <p>If {@code len} characters are not available, or the
    2733     * String is {@code null}, the String will be returned without
    2734     * an exception. An empty String is returned if len is negative.</p>
    2735     *
    2736     * <pre>
    2737     * StringUtils.left(null, *)    = null
    2738     * StringUtils.left(*, -ve)     = ""
    2739     * StringUtils.left("", *)      = ""
    2740     * StringUtils.left("abc", 0)   = ""
    2741     * StringUtils.left("abc", 2)   = "ab"
    2742     * StringUtils.left("abc", 4)   = "abc"
    2743     * </pre>
    2744     *
    2745     * @param str  the String to get the leftmost characters from, may be null
    2746     * @param len  the length of the required String
    2747     * @return the leftmost characters, {@code null} if null String input
    2748     */
    2749    public static String left(final String str, final int len) {
    2750        if (str == null) {
    2751            return null;
    2752        }
    2753        if (len < 0) {
    2754            return EMPTY;
    2755        }
    2756        if (str.length() <= len) {
    2757            return str;
    2758        }
    2759        return str.substring(0, len);
    2760    }
    2761
    2762    /**
    2763     * <p>Gets the rightmost {@code len} characters of a String.</p>
    2764     *
    2765     * <p>If {@code len} characters are not available, or the String
    2766     * is {@code null}, the String will be returned without an
    2767     * an exception. An empty String is returned if len is negative.</p>
    2768     *
    2769     * <pre>
    2770     * StringUtils.right(null, *)    = null
    2771     * StringUtils.right(*, -ve)     = ""
    2772     * StringUtils.right("", *)      = ""
    2773     * StringUtils.right("abc", 0)   = ""
    2774     * StringUtils.right("abc", 2)   = "bc"
    2775     * StringUtils.right("abc", 4)   = "abc"
    2776     * </pre>
    2777     *
    2778     * @param str  the String to get the rightmost characters from, may be null
    2779     * @param len  the length of the required String
    2780     * @return the rightmost characters, {@code null} if null String input
    2781     */
    2782    public static String right(final String str, final int len) {
    2783        if (str == null) {
    2784            return null;
    2785        }
    2786        if (len < 0) {
    2787            return EMPTY;
    2788        }
    2789        if (str.length() <= len) {
    2790            return str;
    2791        }
    2792        return str.substring(str.length() - len);
    2793    }
    2794
    2795    /**
    2796     * <p>Gets {@code len} characters from the middle of a String.</p>
    2797     *
    2798     * <p>If {@code len} characters are not available, the remainder
    2799     * of the String will be returned without an exception. If the
    2800     * String is {@code null}, {@code null} will be returned.
    2801     * An empty String is returned if len is negative or exceeds the
    2802     * length of {@code str}.</p>
    2803     *
    2804     * <pre>
    2805     * StringUtils.mid(null, *, *)    = null
    2806     * StringUtils.mid(*, *, -ve)     = ""
    2807     * StringUtils.mid("", 0, *)      = ""
    2808     * StringUtils.mid("abc", 0, 2)   = "ab"
    2809     * StringUtils.mid("abc", 0, 4)   = "abc"
    2810     * StringUtils.mid("abc", 2, 4)   = "c"
    2811     * StringUtils.mid("abc", 4, 2)   = ""
    2812     * StringUtils.mid("abc", -2, 2)  = "ab"
    2813     * </pre>
    2814     *
    2815     * @param str  the String to get the characters from, may be null
    2816     * @param pos  the position to start from, negative treated as zero
    2817     * @param len  the length of the required String
    2818     * @return the middle characters, {@code null} if null String input
    2819     */
    2820    public static String mid(final String str, int pos, final int len) {
    2821        if (str == null) {
    2822            return null;
    2823        }
    2824        if (len < 0 || pos > str.length()) {
    2825            return EMPTY;
    2826        }
    2827        if (pos < 0) {
    2828            pos = 0;
    2829        }
    2830        if (str.length() <= pos + len) {
    2831            return str.substring(pos);
    2832        }
    2833        return str.substring(pos, pos + len);
    2834    }
    2835
    2836    private static StringBuilder newStringBuilder(final int noOfItems) {
    2837        return new StringBuilder(noOfItems * 16);
    2838    }
    2839
    2840    // SubStringAfter/SubStringBefore
    2841    //-----------------------------------------------------------------------
    2842    /**
    2843     * <p>Gets the substring before the first occurrence of a separator.
    2844     * The separator is not returned.</p>
    2845     *
    2846     * <p>A {@code null} string input will return {@code null}.
    2847     * An empty ("") string input will return the empty string.
    2848     * A {@code null} separator will return the input string.</p>
    2849     *
    2850     * <p>If nothing is found, the string input is returned.</p>
    2851     *
    2852     * <pre>
    2853     * StringUtils.substringBefore(null, *)      = null
    2854     * StringUtils.substringBefore("", *)        = ""
    2855     * StringUtils.substringBefore("abc", "a")   = ""
    2856     * StringUtils.substringBefore("abcba", "b") = "a"
    2857     * StringUtils.substringBefore("abc", "c")   = "ab"
    2858     * StringUtils.substringBefore("abc", "d")   = "abc"
    2859     * StringUtils.substringBefore("abc", "")    = ""
    2860     * StringUtils.substringBefore("abc", null)  = "abc"
    2861     * </pre>
    2862     *
    2863     * @param str  the String to get a substring from, may be null
    2864     * @param separator  the String to search for, may be null
    2865     * @return the substring before the first occurrence of the separator,
    2866     *  {@code null} if null String input
    2867     * @since 2.0
    2868     */
    2869    public static String substringBefore(final String str, final String separator) {
    2870        if (isEmpty(str) || separator == null) {
    2871            return str;
    2872        }
    2873        if (separator.isEmpty()) {
    2874            return EMPTY;
    2875        }
    2876        final int pos = str.indexOf(separator);
    2877        if (pos == INDEX_NOT_FOUND) {
    2878            return str;
    2879        }
    2880        return str.substring(0, pos);
    2881    }
    2882
    2883    /**
    2884     * <p>Gets the substring after the first occurrence of a separator.
    2885     * The separator is not returned.</p>
    2886     *
    2887     * <p>A {@code null} string input will return {@code null}.
    2888     * An empty ("") string input will return the empty string.
    2889     * A {@code null} separator will return the empty string if the
    2890     * input string is not {@code null}.</p>
    2891     *
    2892     * <p>If nothing is found, the empty string is returned.</p>
    2893     *
    2894     * <pre>
    2895     * StringUtils.substringAfter(null, *)      = null
    2896     * StringUtils.substringAfter("", *)        = ""
    2897     * StringUtils.substringAfter(*, null)      = ""
    2898     * StringUtils.substringAfter("abc", "a")   = "bc"
    2899     * StringUtils.substringAfter("abcba", "b") = "cba"
    2900     * StringUtils.substringAfter("abc", "c")   = ""
    2901     * StringUtils.substringAfter("abc", "d")   = ""
    2902     * StringUtils.substringAfter("abc", "")    = "abc"
    2903     * </pre>
    2904     *
    2905     * @param str  the String to get a substring from, may be null
    2906     * @param separator  the String to search for, may be null
    2907     * @return the substring after the first occurrence of the separator,
    2908     *  {@code null} if null String input
    2909     * @since 2.0
    2910     */
    2911    public static String substringAfter(final String str, final String separator) {
    2912        if (isEmpty(str)) {
    2913            return str;
    2914        }
    2915        if (separator == null) {
    2916            return EMPTY;
    2917        }
    2918        final int pos = str.indexOf(separator);
    2919        if (pos == INDEX_NOT_FOUND) {
    2920            return EMPTY;
    2921        }
    2922        return str.substring(pos + separator.length());
    2923    }
    2924
    2925    /**
    2926     * <p>Gets the substring before the last occurrence of a separator.
    2927     * The separator is not returned.</p>
    2928     *
    2929     * <p>A {@code null} string input will return {@code null}.
    2930     * An empty ("") string input will return the empty string.
    2931     * An empty or {@code null} separator will return the input string.</p>
    2932     *
    2933     * <p>If nothing is found, the string input is returned.</p>
    2934     *
    2935     * <pre>
    2936     * StringUtils.substringBeforeLast(null, *)      = null
    2937     * StringUtils.substringBeforeLast("", *)        = ""
    2938     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    2939     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    2940     * StringUtils.substringBeforeLast("a", "a")     = ""
    2941     * StringUtils.substringBeforeLast("a", "z")     = "a"
    2942     * StringUtils.substringBeforeLast("a", null)    = "a"
    2943     * StringUtils.substringBeforeLast("a", "")      = "a"
    2944     * </pre>
    2945     *
    2946     * @param str  the String to get a substring from, may be null
    2947     * @param separator  the String to search for, may be null
    2948     * @return the substring before the last occurrence of the separator,
    2949     *  {@code null} if null String input
    2950     * @since 2.0
    2951     */
    2952    public static String substringBeforeLast(final String str, final String separator) {
    2953        if (isEmpty(str) || isEmpty(separator)) {
    2954            return str;
    2955        }
    2956        final int pos = str.lastIndexOf(separator);
    2957        if (pos == INDEX_NOT_FOUND) {
    2958            return str;
    2959        }
    2960        return str.substring(0, pos);
    2961    }
    2962
    2963    /**
    2964     * <p>Gets the substring after the last occurrence of a separator.
    2965     * The separator is not returned.</p>
    2966     *
    2967     * <p>A {@code null} string input will return {@code null}.
    2968     * An empty ("") string input will return the empty string.
    2969     * An empty or {@code null} separator will return the empty string if
    2970     * the input string is not {@code null}.</p>
    2971     *
    2972     * <p>If nothing is found, the empty string is returned.</p>
    2973     *
    2974     * <pre>
    2975     * StringUtils.substringAfterLast(null, *)      = null
    2976     * StringUtils.substringAfterLast("", *)        = ""
    2977     * StringUtils.substringAfterLast(*, "")        = ""
    2978     * StringUtils.substringAfterLast(*, null)      = ""
    2979     * StringUtils.substringAfterLast("abc", "a")   = "bc"
    2980     * StringUtils.substringAfterLast("abcba", "b") = "a"
    2981     * StringUtils.substringAfterLast("abc", "c")   = ""
    2982     * StringUtils.substringAfterLast("a", "a")     = ""
    2983     * StringUtils.substringAfterLast("a", "z")     = ""
    2984     * </pre>
    2985     *
    2986     * @param str  the String to get a substring from, may be null
    2987     * @param separator  the String to search for, may be null
    2988     * @return the substring after the last occurrence of the separator,
    2989     *  {@code null} if null String input
    2990     * @since 2.0
    2991     */
    2992    public static String substringAfterLast(final String str, final String separator) {
    2993        if (isEmpty(str)) {
    2994            return str;
    2995        }
    2996        if (isEmpty(separator)) {
    2997            return EMPTY;
    2998        }
    2999        final int pos = str.lastIndexOf(separator);
    3000        if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
    3001            return EMPTY;
    3002        }
    3003        return str.substring(pos + separator.length());
    3004    }
    3005
    3006    // Substring between
    3007    //-----------------------------------------------------------------------
    3008    /**
    3009     * <p>Gets the String that is nested in between two instances of the
    3010     * same String.</p>
    3011     *
    3012     * <p>A {@code null} input String returns {@code null}.
    3013     * A {@code null} tag returns {@code null}.</p>
    3014     *
    3015     * <pre>
    3016     * StringUtils.substringBetween(null, *)            = null
    3017     * StringUtils.substringBetween("", "")             = ""
    3018     * StringUtils.substringBetween("", "tag")          = null
    3019     * StringUtils.substringBetween("tagabctag", null)  = null
    3020     * StringUtils.substringBetween("tagabctag", "")    = ""
    3021     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    3022     * </pre>
    3023     *
    3024     * @param str  the String containing the substring, may be null
    3025     * @param tag  the String before and after the substring, may be null
    3026     * @return the substring, {@code null} if no match
    3027     * @since 2.0
    3028     */
    3029    public static String substringBetween(final String str, final String tag) {
    3030        return substringBetween(str, tag, tag);
    3031    }
    3032
    3033    /**
    3034     * <p>Gets the String that is nested in between two Strings.
    3035     * Only the first match is returned.</p>
    3036     *
    3037     * <p>A {@code null} input String returns {@code null}.
    3038     * A {@code null} open/close returns {@code null} (no match).
    3039     * An empty ("") open and close returns an empty string.</p>
    3040     *
    3041     * <pre>
    3042     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    3043     * StringUtils.substringBetween(null, *, *)          = null
    3044     * StringUtils.substringBetween(*, null, *)          = null
    3045     * StringUtils.substringBetween(*, *, null)          = null
    3046     * StringUtils.substringBetween("", "", "")          = ""
    3047     * StringUtils.substringBetween("", "", "]")         = null
    3048     * StringUtils.substringBetween("", "[", "]")        = null
    3049     * StringUtils.substringBetween("yabcz", "", "")     = ""
    3050     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    3051     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    3052     * </pre>
    3053     *
    3054     * @param str  the String containing the substring, may be null
    3055     * @param open  the String before the substring, may be null
    3056     * @param close  the String after the substring, may be null
    3057     * @return the substring, {@code null} if no match
    3058     * @since 2.0
    3059     */
    3060    public static String substringBetween(final String str, final String open, final String close) {
    3061        if (str == null || open == null || close == null) {
    3062            return null;
    3063        }
    3064        final int start = str.indexOf(open);
    3065        if (start != INDEX_NOT_FOUND) {
    3066            final int end = str.indexOf(close, start + open.length());
    3067            if (end != INDEX_NOT_FOUND) {
    3068                return str.substring(start + open.length(), end);
    3069            }
    3070        }
    3071        return null;
    3072    }
    3073
    3074    /**
    3075     * <p>Searches a String for substrings delimited by a start and end tag,
    3076     * returning all matching substrings in an array.</p>
    3077     *
    3078     * <p>A {@code null} input String returns {@code null}.
    3079     * A {@code null} open/close returns {@code null} (no match).
    3080     * An empty ("") open/close returns {@code null} (no match).</p>
    3081     *
    3082     * <pre>
    3083     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    3084     * StringUtils.substringsBetween(null, *, *)            = null
    3085     * StringUtils.substringsBetween(*, null, *)            = null
    3086     * StringUtils.substringsBetween(*, *, null)            = null
    3087     * StringUtils.substringsBetween("", "[", "]")          = []
    3088     * </pre>
    3089     *
    3090     * @param str  the String containing the substrings, null returns null, empty returns empty
    3091     * @param open  the String identifying the start of the substring, empty returns null
    3092     * @param close  the String identifying the end of the substring, empty returns null
    3093     * @return a String Array of substrings, or {@code null} if no match
    3094     * @since 2.3
    3095     */
    3096    public static String[] substringsBetween(final String str, final String open, final String close) {
    3097        if (str == null || isEmpty(open) || isEmpty(close)) {
    3098            return null;
    3099        }
    3100        final int strLen = str.length();
    3101        if (strLen == 0) {
    3102            return ArrayUtils.EMPTY_STRING_ARRAY;
    3103        }
    3104        final int closeLen = close.length();
    3105        final int openLen = open.length();
    3106        final List<String> list = new ArrayList<>();
    3107        int pos = 0;
    3108        while (pos < strLen - closeLen) {
    3109            int start = str.indexOf(open, pos);
    3110            if (start < 0) {
    3111                break;
    3112            }
    3113            start += openLen;
    3114            final int end = str.indexOf(close, start);
    3115            if (end < 0) {
    3116                break;
    3117            }
    3118            list.add(str.substring(start, end));
    3119            pos = end + closeLen;
    3120        }
    3121        if (list.isEmpty()) {
    3122            return null;
    3123        }
    3124        return list.toArray(new String [list.size()]);
    3125    }
    3126
    3127    // Nested extraction
    3128    //-----------------------------------------------------------------------
    3129
    3130    // Splitting
    3131    //-----------------------------------------------------------------------
    3132    /**
    3133     * <p>Splits the provided text into an array, using whitespace as the
    3134     * separator.
    3135     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3136     *
    3137     * <p>The separator is not included in the returned String array.
    3138     * Adjacent separators are treated as one separator.
    3139     * For more control over the split use the StrTokenizer class.</p>
    3140     *
    3141     * <p>A {@code null} input String returns {@code null}.</p>
    3142     *
    3143     * <pre>
    3144     * StringUtils.split(null)       = null
    3145     * StringUtils.split("")         = []
    3146     * StringUtils.split("abc def")  = ["abc", "def"]
    3147     * StringUtils.split("abc  def") = ["abc", "def"]
    3148     * StringUtils.split(" abc ")    = ["abc"]
    3149     * </pre>
    3150     *
    3151     * @param str  the String to parse, may be null
    3152     * @return an array of parsed Strings, {@code null} if null String input
    3153     */
    3154    public static String[] split(final String str) {
    3155        return split(str, null, -1);
    3156    }
    3157
    3158    /**
    3159     * <p>Splits the provided text into an array, separator specified.
    3160     * This is an alternative to using StringTokenizer.</p>
    3161     *
    3162     * <p>The separator is not included in the returned String array.
    3163     * Adjacent separators are treated as one separator.
    3164     * For more control over the split use the StrTokenizer class.</p>
    3165     *
    3166     * <p>A {@code null} input String returns {@code null}.</p>
    3167     *
    3168     * <pre>
    3169     * StringUtils.split(null, *)         = null
    3170     * StringUtils.split("", *)           = []
    3171     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    3172     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    3173     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    3174     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    3175     * </pre>
    3176     *
    3177     * @param str  the String to parse, may be null
    3178     * @param separatorChar  the character used as the delimiter
    3179     * @return an array of parsed Strings, {@code null} if null String input
    3180     * @since 2.0
    3181     */
    3182    public static String[] split(final String str, final char separatorChar) {
    3183        return splitWorker(str, separatorChar, false);
    3184    }
    3185
    3186    /**
    3187     * <p>Splits the provided text into an array, separators specified.
    3188     * This is an alternative to using StringTokenizer.</p>
    3189     *
    3190     * <p>The separator is not included in the returned String array.
    3191     * Adjacent separators are treated as one separator.
    3192     * For more control over the split use the StrTokenizer class.</p>
    3193     *
    3194     * <p>A {@code null} input String returns {@code null}.
    3195     * A {@code null} separatorChars splits on whitespace.</p>
    3196     *
    3197     * <pre>
    3198     * StringUtils.split(null, *)         = null
    3199     * StringUtils.split("", *)           = []
    3200     * StringUtils.split("abc def", null) = ["abc", "def"]
    3201     * StringUtils.split("abc def", " ")  = ["abc", "def"]
    3202     * StringUtils.split("abc  def", " ") = ["abc", "def"]
    3203     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    3204     * </pre>
    3205     *
    3206     * @param str  the String to parse, may be null
    3207     * @param separatorChars  the characters used as the delimiters,
    3208     *  {@code null} splits on whitespace
    3209     * @return an array of parsed Strings, {@code null} if null String input
    3210     */
    3211    public static String[] split(final String str, final String separatorChars) {
    3212        return splitWorker(str, separatorChars, -1, false);
    3213    }
    3214
    3215    /**
    3216     * <p>Splits the provided text into an array with a maximum length,
    3217     * separators specified.</p>
    3218     *
    3219     * <p>The separator is not included in the returned String array.
    3220     * Adjacent separators are treated as one separator.</p>
    3221     *
    3222     * <p>A {@code null} input String returns {@code null}.
    3223     * A {@code null} separatorChars splits on whitespace.</p>
    3224     *
    3225     * <p>If more than {@code max} delimited substrings are found, the last
    3226     * returned string includes all characters after the first {@code max - 1}
    3227     * returned strings (including separator characters).</p>
    3228     *
    3229     * <pre>
    3230     * StringUtils.split(null, *, *)            = null
    3231     * StringUtils.split("", *, *)              = []
    3232     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
    3233     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
    3234     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    3235     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    3236     * </pre>
    3237     *
    3238     * @param str  the String to parse, may be null
    3239     * @param separatorChars  the characters used as the delimiters,
    3240     *  {@code null} splits on whitespace
    3241     * @param max  the maximum number of elements to include in the
    3242     *  array. A zero or negative value implies no limit
    3243     * @return an array of parsed Strings, {@code null} if null String input
    3244     */
    3245    public static String[] split(final String str, final String separatorChars, final int max) {
    3246        return splitWorker(str, separatorChars, max, false);
    3247    }
    3248
    3249    /**
    3250     * <p>Splits the provided text into an array, separator string specified.</p>
    3251     *
    3252     * <p>The separator(s) will not be included in the returned String array.
    3253     * Adjacent separators are treated as one separator.</p>
    3254     *
    3255     * <p>A {@code null} input String returns {@code null}.
    3256     * A {@code null} separator splits on whitespace.</p>
    3257     *
    3258     * <pre>
    3259     * StringUtils.splitByWholeSeparator(null, *)               = null
    3260     * StringUtils.splitByWholeSeparator("", *)                 = []
    3261     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    3262     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    3263     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    3264     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    3265     * </pre>
    3266     *
    3267     * @param str  the String to parse, may be null
    3268     * @param separator  String containing the String to be used as a delimiter,
    3269     *  {@code null} splits on whitespace
    3270     * @return an array of parsed Strings, {@code null} if null String was input
    3271     */
    3272    public static String[] splitByWholeSeparator(final String str, final String separator) {
    3273        return splitByWholeSeparatorWorker(str, separator, -1, false ) ;
    3274    }
    3275
    3276    /**
    3277     * <p>Splits the provided text into an array, separator string specified.
    3278     * Returns a maximum of {@code max} substrings.</p>
    3279     *
    3280     * <p>The separator(s) will not be included in the returned String array.
    3281     * Adjacent separators are treated as one separator.</p>
    3282     *
    3283     * <p>A {@code null} input String returns {@code null}.
    3284     * A {@code null} separator splits on whitespace.</p>
    3285     *
    3286     * <pre>
    3287     * StringUtils.splitByWholeSeparator(null, *, *)               = null
    3288     * StringUtils.splitByWholeSeparator("", *, *)                 = []
    3289     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
    3290     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    3291     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    3292     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    3293     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    3294     * </pre>
    3295     *
    3296     * @param str  the String to parse, may be null
    3297     * @param separator  String containing the String to be used as a delimiter,
    3298     *  {@code null} splits on whitespace
    3299     * @param max  the maximum number of elements to include in the returned
    3300     *  array. A zero or negative value implies no limit.
    3301     * @return an array of parsed Strings, {@code null} if null String was input
    3302     */
    3303    public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
    3304        return splitByWholeSeparatorWorker(str, separator, max, false);
    3305    }
    3306
    3307    /**
    3308     * <p>Splits the provided text into an array, separator string specified. </p>
    3309     *
    3310     * <p>The separator is not included in the returned String array.
    3311     * Adjacent separators are treated as separators for empty tokens.
    3312     * For more control over the split use the StrTokenizer class.</p>
    3313     *
    3314     * <p>A {@code null} input String returns {@code null}.
    3315     * A {@code null} separator splits on whitespace.</p>
    3316     *
    3317     * <pre>
    3318     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    3319     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    3320     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    3321     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    3322     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    3323     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    3324     * </pre>
    3325     *
    3326     * @param str  the String to parse, may be null
    3327     * @param separator  String containing the String to be used as a delimiter,
    3328     *  {@code null} splits on whitespace
    3329     * @return an array of parsed Strings, {@code null} if null String was input
    3330     * @since 2.4
    3331     */
    3332    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
    3333        return splitByWholeSeparatorWorker(str, separator, -1, true);
    3334    }
    3335
    3336    /**
    3337     * <p>Splits the provided text into an array, separator string specified.
    3338     * Returns a maximum of {@code max} substrings.</p>
    3339     *
    3340     * <p>The separator is not included in the returned String array.
    3341     * Adjacent separators are treated as separators for empty tokens.
    3342     * For more control over the split use the StrTokenizer class.</p>
    3343     *
    3344     * <p>A {@code null} input String returns {@code null}.
    3345     * A {@code null} separator splits on whitespace.</p>
    3346     *
    3347     * <pre>
    3348     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    3349     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    3350     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    3351     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    3352     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    3353     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    3354     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    3355     * </pre>
    3356     *
    3357     * @param str  the String to parse, may be null
    3358     * @param separator  String containing the String to be used as a delimiter,
    3359     *  {@code null} splits on whitespace
    3360     * @param max  the maximum number of elements to include in the returned
    3361     *  array. A zero or negative value implies no limit.
    3362     * @return an array of parsed Strings, {@code null} if null String was input
    3363     * @since 2.4
    3364     */
    3365    public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
    3366        return splitByWholeSeparatorWorker(str, separator, max, true);
    3367    }
    3368
    3369    /**
    3370     * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
    3371     *
    3372     * @param str  the String to parse, may be {@code null}
    3373     * @param separator  String containing the String to be used as a delimiter,
    3374     *  {@code null} splits on whitespace
    3375     * @param max  the maximum number of elements to include in the returned
    3376     *  array. A zero or negative value implies no limit.
    3377     * @param preserveAllTokens if {@code true}, adjacent separators are
    3378     * treated as empty token separators; if {@code false}, adjacent
    3379     * separators are treated as one separator.
    3380     * @return an array of parsed Strings, {@code null} if null String input
    3381     * @since 2.4
    3382     */
    3383    private static String[] splitByWholeSeparatorWorker(
    3384            final String str, final String separator, final int max, final boolean preserveAllTokens) {
    3385        if (str == null) {
    3386            return null;
    3387        }
    3388
    3389        final int len = str.length();
    3390
    3391        if (len == 0) {
    3392            return ArrayUtils.EMPTY_STRING_ARRAY;
    3393        }
    3394
    3395        if (separator == null || EMPTY.equals(separator)) {
    3396            // Split on whitespace.
    3397            return splitWorker(str, null, max, preserveAllTokens);
    3398        }
    3399
    3400        final int separatorLength = separator.length();
    3401
    3402        final ArrayList<String> substrings = new ArrayList<>();
    3403        int numberOfSubstrings = 0;
    3404        int beg = 0;
    3405        int end = 0;
    3406        while (end < len) {
    3407            end = str.indexOf(separator, beg);
    3408
    3409            if (end > -1) {
    3410                if (end > beg) {
    3411                    numberOfSubstrings += 1;
    3412
    3413                    if (numberOfSubstrings == max) {
    3414                        end = len;
    3415                        substrings.add(str.substring(beg));
    3416                    } else {
    3417                        // The following is OK, because String.substring( beg, end ) excludes
    3418                        // the character at the position 'end'.
    3419                        substrings.add(str.substring(beg, end));
    3420
    3421                        // Set the starting point for the next search.
    3422                        // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    3423                        // which is the right calculation:
    3424                        beg = end + separatorLength;
    3425                    }
    3426                } else {
    3427                    // We found a consecutive occurrence of the separator, so skip it.
    3428                    if (preserveAllTokens) {
    3429                        numberOfSubstrings += 1;
    3430                        if (numberOfSubstrings == max) {
    3431                            end = len;
    3432                            substrings.add(str.substring(beg));
    3433                        } else {
    3434                            substrings.add(EMPTY);
    3435                        }
    3436                    }
    3437                    beg = end + separatorLength;
    3438                }
    3439            } else {
    3440                // String.substring( beg ) goes from 'beg' to the end of the String.
    3441                substrings.add(str.substring(beg));
    3442                end = len;
    3443            }
    3444        }
    3445
    3446        return substrings.toArray(new String[substrings.size()]);
    3447    }
    3448
    3449    // -----------------------------------------------------------------------
    3450    /**
    3451     * <p>Splits the provided text into an array, using whitespace as the
    3452     * separator, preserving all tokens, including empty tokens created by
    3453     * adjacent separators. This is an alternative to using StringTokenizer.
    3454     * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    3455     *
    3456     * <p>The separator is not included in the returned String array.
    3457     * Adjacent separators are treated as separators for empty tokens.
    3458     * For more control over the split use the StrTokenizer class.</p>
    3459     *
    3460     * <p>A {@code null} input String returns {@code null}.</p>
    3461     *
    3462     * <pre>
    3463     * StringUtils.splitPreserveAllTokens(null)       = null
    3464     * StringUtils.splitPreserveAllTokens("")         = []
    3465     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    3466     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    3467     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    3468     * </pre>
    3469     *
    3470     * @param str  the String to parse, may be {@code null}
    3471     * @return an array of parsed Strings, {@code null} if null String input
    3472     * @since 2.1
    3473     */
    3474    public static String[] splitPreserveAllTokens(final String str) {
    3475        return splitWorker(str, null, -1, true);
    3476    }
    3477
    3478    /**
    3479     * <p>Splits the provided text into an array, separator specified,
    3480     * preserving all tokens, including empty tokens created by adjacent
    3481     * separators. This is an alternative to using StringTokenizer.</p>
    3482     *
    3483     * <p>The separator is not included in the returned String array.
    3484     * Adjacent separators are treated as separators for empty tokens.
    3485     * For more control over the split use the StrTokenizer class.</p>
    3486     *
    3487     * <p>A {@code null} input String returns {@code null}.</p>
    3488     *
    3489     * <pre>
    3490     * StringUtils.splitPreserveAllTokens(null, *)         = null
    3491     * StringUtils.splitPreserveAllTokens("", *)           = []
    3492     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    3493     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    3494     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    3495     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    3496     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    3497     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    3498     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
    3499     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
    3500     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
    3501     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
    3502     * </pre>
    3503     *
    3504     * @param str  the String to parse, may be {@code null}
    3505     * @param separatorChar  the character used as the delimiter,
    3506     *  {@code null} splits on whitespace
    3507     * @return an array of parsed Strings, {@code null} if null String input
    3508     * @since 2.1
    3509     */
    3510    public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
    3511        return splitWorker(str, separatorChar, true);
    3512    }
    3513
    3514    /**
    3515     * Performs the logic for the {@code split} and
    3516     * {@code splitPreserveAllTokens} methods that do not return a
    3517     * maximum array length.
    3518     *
    3519     * @param str  the String to parse, may be {@code null}
    3520     * @param separatorChar the separate character
    3521     * @param preserveAllTokens if {@code true}, adjacent separators are
    3522     * treated as empty token separators; if {@code false}, adjacent
    3523     * separators are treated as one separator.
    3524     * @return an array of parsed Strings, {@code null} if null String input
    3525     */
    3526    private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
    3527        // Performance tuned for 2.0 (JDK1.4)
    3528
    3529        if (str == null) {
    3530            return null;
    3531        }
    3532        final int len = str.length();
    3533        if (len == 0) {
    3534            return ArrayUtils.EMPTY_STRING_ARRAY;
    3535        }
    3536        final List<String> list = new ArrayList<>();
    3537        int i = 0, start = 0;
    3538        boolean match = false;
    3539        boolean lastMatch = false;
    3540        while (i < len) {
    3541            if (str.charAt(i) == separatorChar) {
    3542                if (match || preserveAllTokens) {
    3543                    list.add(str.substring(start, i));
    3544                    match = false;
    3545                    lastMatch = true;
    3546                }
    3547                start = ++i;
    3548                continue;
    3549            }
    3550            lastMatch = false;
    3551            match = true;
    3552            i++;
    3553        }
    3554        if (match || preserveAllTokens && lastMatch) {
    3555            list.add(str.substring(start, i));
    3556        }
    3557        return list.toArray(new String[list.size()]);
    3558    }
    3559
    3560    /**
    3561     * <p>Splits the provided text into an array, separators specified,
    3562     * preserving all tokens, including empty tokens created by adjacent
    3563     * separators. This is an alternative to using StringTokenizer.</p>
    3564     *
    3565     * <p>The separator is not included in the returned String array.
    3566     * Adjacent separators are treated as separators for empty tokens.
    3567     * For more control over the split use the StrTokenizer class.</p>
    3568     *
    3569     * <p>A {@code null} input String returns {@code null}.
    3570     * A {@code null} separatorChars splits on whitespace.</p>
    3571     *
    3572     * <pre>
    3573     * StringUtils.splitPreserveAllTokens(null, *)           = null
    3574     * StringUtils.splitPreserveAllTokens("", *)             = []
    3575     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    3576     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    3577     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
    3578     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    3579     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    3580     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    3581     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
    3582     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
    3583     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
    3584     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
    3585     * </pre>
    3586     *
    3587     * @param str  the String to parse, may be {@code null}
    3588     * @param separatorChars  the characters used as the delimiters,
    3589     *  {@code null} splits on whitespace
    3590     * @return an array of parsed Strings, {@code null} if null String input
    3591     * @since 2.1
    3592     */
    3593    public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
    3594        return splitWorker(str, separatorChars, -1, true);
    3595    }
    3596
    3597    /**
    3598     * <p>Splits the provided text into an array with a maximum length,
    3599     * separators specified, preserving all tokens, including empty tokens
    3600     * created by adjacent separators.</p>
    3601     *
    3602     * <p>The separator is not included in the returned String array.
    3603     * Adjacent separators are treated as separators for empty tokens.
    3604     * Adjacent separators are treated as one separator.</p>
    3605     *
    3606     * <p>A {@code null} input String returns {@code null}.
    3607     * A {@code null} separatorChars splits on whitespace.</p>
    3608     *
    3609     * <p>If more than {@code max} delimited substrings are found, the last
    3610     * returned string includes all characters after the first {@code max - 1}
    3611     * returned strings (including separator characters).</p>
    3612     *
    3613     * <pre>
    3614     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    3615     * StringUtils.splitPreserveAllTokens("", *, *)              = []
    3616     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
    3617     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
    3618     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    3619     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    3620     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    3621     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    3622     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    3623     * </pre>
    3624     *
    3625     * @param str  the String to parse, may be {@code null}
    3626     * @param separatorChars  the characters used as the delimiters,
    3627     *  {@code null} splits on whitespace
    3628     * @param max  the maximum number of elements to include in the
    3629     *  array. A zero or negative value implies no limit
    3630     * @return an array of parsed Strings, {@code null} if null String input
    3631     * @since 2.1
    3632     */
    3633    public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
    3634        return splitWorker(str, separatorChars, max, true);
    3635    }
    3636
    3637    /**
    3638     * Performs the logic for the {@code split} and
    3639     * {@code splitPreserveAllTokens} methods that return a maximum array
    3640     * length.
    3641     *
    3642     * @param str  the String to parse, may be {@code null}
    3643     * @param separatorChars the separate character
    3644     * @param max  the maximum number of elements to include in the
    3645     *  array. A zero or negative value implies no limit.
    3646     * @param preserveAllTokens if {@code true}, adjacent separators are
    3647     * treated as empty token separators; if {@code false}, adjacent
    3648     * separators are treated as one separator.
    3649     * @return an array of parsed Strings, {@code null} if null String input
    3650     */
    3651    private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
    3652        // Performance tuned for 2.0 (JDK1.4)
    3653        // Direct code is quicker than StringTokenizer.
    3654        // Also, StringTokenizer uses isSpace() not isWhitespace()
    3655
    3656        if (str == null) {
    3657            return null;
    3658        }
    3659        final int len = str.length();
    3660        if (len == 0) {
    3661            return ArrayUtils.EMPTY_STRING_ARRAY;
    3662        }
    3663        final List<String> list = new ArrayList<>();
    3664        int sizePlus1 = 1;
    3665        int i = 0, start = 0;
    3666        boolean match = false;
    3667        boolean lastMatch = false;
    3668        if (separatorChars == null) {
    3669            // Null separator means use whitespace
    3670            while (i < len) {
    3671                if (Character.isWhitespace(str.charAt(i))) {
    3672                    if (match || preserveAllTokens) {
    3673                        lastMatch = true;
    3674                        if (sizePlus1++ == max) {
    3675                            i = len;
    3676                            lastMatch = false;
    3677                        }
    3678                        list.add(str.substring(start, i));
    3679                        match = false;
    3680                    }
    3681                    start = ++i;
    3682                    continue;
    3683                }
    3684                lastMatch = false;
    3685                match = true;
    3686                i++;
    3687            }
    3688        } else if (separatorChars.length() == 1) {
    3689            // Optimise 1 character case
    3690            final char sep = separatorChars.charAt(0);
    3691            while (i < len) {
    3692                if (str.charAt(i) == sep) {
    3693                    if (match || preserveAllTokens) {
    3694                        lastMatch = true;
    3695                        if (sizePlus1++ == max) {
    3696                            i = len;
    3697                            lastMatch = false;
    3698                        }
    3699                        list.add(str.substring(start, i));
    3700                        match = false;
    3701                    }
    3702                    start = ++i;
    3703                    continue;
    3704                }
    3705                lastMatch = false;
    3706                match = true;
    3707                i++;
    3708            }
    3709        } else {
    3710            // standard case
    3711            while (i < len) {
    3712                if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    3713                    if (match || preserveAllTokens) {
    3714                        lastMatch = true;
    3715                        if (sizePlus1++ == max) {
    3716                            i = len;
    3717                            lastMatch = false;
    3718                        }
    3719                        list.add(str.substring(start, i));
    3720                        match = false;
    3721                    }
    3722                    start = ++i;
    3723                    continue;
    3724                }
    3725                lastMatch = false;
    3726                match = true;
    3727                i++;
    3728            }
    3729        }
    3730        if (match || preserveAllTokens && lastMatch) {
    3731            list.add(str.substring(start, i));
    3732        }
    3733        return list.toArray(new String[list.size()]);
    3734    }
    3735
    3736    /**
    3737     * <p>Splits a String by Character type as returned by
    3738     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    3739     * characters of the same type are returned as complete tokens.
    3740     * <pre>
    3741     * StringUtils.splitByCharacterType(null)         = null
    3742     * StringUtils.splitByCharacterType("")           = []
    3743     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    3744     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    3745     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    3746     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    3747     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    3748     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    3749     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    3750     * </pre>
    3751     * @param str the String to split, may be {@code null}
    3752     * @return an array of parsed Strings, {@code null} if null String input
    3753     * @since 2.4
    3754     */
    3755    public static String[] splitByCharacterType(final String str) {
    3756        return splitByCharacterType(str, false);
    3757    }
    3758
    3759    /**
    3760     * <p>Splits a String by Character type as returned by
    3761     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    3762     * characters of the same type are returned as complete tokens, with the
    3763     * following exception: the character of type
    3764     * {@code Character.UPPERCASE_LETTER}, if any, immediately
    3765     * preceding a token of type {@code Character.LOWERCASE_LETTER}
    3766     * will belong to the following token rather than to the preceding, if any,
    3767     * {@code Character.UPPERCASE_LETTER} token.
    3768     * <pre>
    3769     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    3770     * StringUtils.splitByCharacterTypeCamelCase("")           = []
    3771     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    3772     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    3773     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    3774     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    3775     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    3776     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    3777     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    3778     * </pre>
    3779     * @param str the String to split, may be {@code null}
    3780     * @return an array of parsed Strings, {@code null} if null String input
    3781     * @since 2.4
    3782     */
    3783    public static String[] splitByCharacterTypeCamelCase(final String str) {
    3784        return splitByCharacterType(str, true);
    3785    }
    3786
    3787    /**
    3788     * <p>Splits a String by Character type as returned by
    3789     * {@code java.lang.Character.getType(char)}. Groups of contiguous
    3790     * characters of the same type are returned as complete tokens, with the
    3791     * following exception: if {@code camelCase} is {@code true},
    3792     * the character of type {@code Character.UPPERCASE_LETTER}, if any,
    3793     * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
    3794     * will belong to the following token rather than to the preceding, if any,
    3795     * {@code Character.UPPERCASE_LETTER} token.
    3796     * @param str the String to split, may be {@code null}
    3797     * @param camelCase whether to use so-called "camel-case" for letter types
    3798     * @return an array of parsed Strings, {@code null} if null String input
    3799     * @since 2.4
    3800     */
    3801    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
    3802        if (str == null) {
    3803            return null;
    3804        }
    3805        if (str.isEmpty()) {
    3806            return ArrayUtils.EMPTY_STRING_ARRAY;
    3807        }
    3808        final char[] c = str.toCharArray();
    3809        final List<String> list = new ArrayList<>();
    3810        int tokenStart = 0;
    3811        int currentType = Character.getType(c[tokenStart]);
    3812        for (int pos = tokenStart + 1; pos < c.length; pos++) {
    3813            final int type = Character.getType(c[pos]);
    3814            if (type == currentType) {
    3815                continue;
    3816            }
    3817            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    3818                final int newTokenStart = pos - 1;
    3819                if (newTokenStart != tokenStart) {
    3820                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    3821                    tokenStart = newTokenStart;
    3822                }
    3823            } else {
    3824                list.add(new String(c, tokenStart, pos - tokenStart));
    3825                tokenStart = pos;
    3826            }
    3827            currentType = type;
    3828        }
    3829        list.add(new String(c, tokenStart, c.length - tokenStart));
    3830        return list.toArray(new String[list.size()]);
    3831    }
    3832
    3833    // Joining
    3834    //-----------------------------------------------------------------------
    3835    /**
    3836     * <p>Joins the elements of the provided array into a single String
    3837     * containing the provided list of elements.</p>
    3838     *
    3839     * <p>No separator is added to the joined String.
    3840     * Null objects or empty strings within the array are represented by
    3841     * empty strings.</p>
    3842     *
    3843     * <pre>
    3844     * StringUtils.join(null)            = null
    3845     * StringUtils.join([])              = ""
    3846     * StringUtils.join([null])          = ""
    3847     * StringUtils.join(["a", "b", "c"]) = "abc"
    3848     * StringUtils.join([null, "", "a"]) = "a"
    3849     * </pre>
    3850     *
    3851     * @param <T> the specific type of values to join together
    3852     * @param elements  the values to join together, may be null
    3853     * @return the joined String, {@code null} if null array input
    3854     * @since 2.0
    3855     * @since 3.0 Changed signature to use varargs
    3856     */
    3857    @SafeVarargs
    3858    public static <T> String join(final T... elements) {
    3859        return join(elements, null);
    3860    }
    3861
    3862    /**
    3863     * <p>Joins the elements of the provided array into a single String
    3864     * containing the provided list of elements.</p>
    3865     *
    3866     * <p>No delimiter is added before or after the list.
    3867     * Null objects or empty strings within the array are represented by
    3868     * empty strings.</p>
    3869     *
    3870     * <pre>
    3871     * StringUtils.join(null, *)               = null
    3872     * StringUtils.join([], *)                 = ""
    3873     * StringUtils.join([null], *)             = ""
    3874     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    3875     * StringUtils.join(["a", "b", "c"], null) = "abc"
    3876     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    3877     * </pre>
    3878     *
    3879     * @param array  the array of values to join together, may be null
    3880     * @param separator  the separator character to use
    3881     * @return the joined String, {@code null} if null array input
    3882     * @since 2.0
    3883     */
    3884    public static String join(final Object[] array, final char separator) {
    3885        if (array == null) {
    3886            return null;
    3887        }
    3888        return join(array, separator, 0, array.length);
    3889    }
    3890
    3891    /**
    3892     * <p>
    3893     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3894     * </p>
    3895     *
    3896     * <p>
    3897     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3898     * by empty strings.
    3899     * </p>
    3900     *
    3901     * <pre>
    3902     * StringUtils.join(null, *)               = null
    3903     * StringUtils.join([], *)                 = ""
    3904     * StringUtils.join([null], *)             = ""
    3905     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3906     * StringUtils.join([1, 2, 3], null) = "123"
    3907     * </pre>
    3908     *
    3909     * @param array
    3910     *            the array of values to join together, may be null
    3911     * @param separator
    3912     *            the separator character to use
    3913     * @return the joined String, {@code null} if null array input
    3914     * @since 3.2
    3915     */
    3916    public static String join(final long[] array, final char separator) {
    3917        if (array == null) {
    3918            return null;
    3919        }
    3920        return join(array, separator, 0, array.length);
    3921    }
    3922
    3923    /**
    3924     * <p>
    3925     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3926     * </p>
    3927     *
    3928     * <p>
    3929     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3930     * by empty strings.
    3931     * </p>
    3932     *
    3933     * <pre>
    3934     * StringUtils.join(null, *)               = null
    3935     * StringUtils.join([], *)                 = ""
    3936     * StringUtils.join([null], *)             = ""
    3937     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3938     * StringUtils.join([1, 2, 3], null) = "123"
    3939     * </pre>
    3940     *
    3941     * @param array
    3942     *            the array of values to join together, may be null
    3943     * @param separator
    3944     *            the separator character to use
    3945     * @return the joined String, {@code null} if null array input
    3946     * @since 3.2
    3947     */
    3948    public static String join(final int[] array, final char separator) {
    3949        if (array == null) {
    3950            return null;
    3951        }
    3952        return join(array, separator, 0, array.length);
    3953    }
    3954
    3955    /**
    3956     * <p>
    3957     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3958     * </p>
    3959     *
    3960     * <p>
    3961     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3962     * by empty strings.
    3963     * </p>
    3964     *
    3965     * <pre>
    3966     * StringUtils.join(null, *)               = null
    3967     * StringUtils.join([], *)                 = ""
    3968     * StringUtils.join([null], *)             = ""
    3969     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    3970     * StringUtils.join([1, 2, 3], null) = "123"
    3971     * </pre>
    3972     *
    3973     * @param array
    3974     *            the array of values to join together, may be null
    3975     * @param separator
    3976     *            the separator character to use
    3977     * @return the joined String, {@code null} if null array input
    3978     * @since 3.2
    3979     */
    3980    public static String join(final short[] array, final char separator) {
    3981        if (array == null) {
    3982            return null;
    3983        }
    3984        return join(array, separator, 0, array.length);
    3985    }
    3986
    3987    /**
    3988     * <p>
    3989     * Joins the elements of the provided array into a single String containing the provided list of elements.
    3990     * </p>
    3991     *
    3992     * <p>
    3993     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    3994     * by empty strings.
    3995     * </p>
    3996     *
    3997     * <pre>
    3998     * StringUtils.join(null, *)               = null
    3999     * StringUtils.join([], *)                 = ""
    4000     * StringUtils.join([null], *)             = ""
    4001     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4002     * StringUtils.join([1, 2, 3], null) = "123"
    4003     * </pre>
    4004     *
    4005     * @param array
    4006     *            the array of values to join together, may be null
    4007     * @param separator
    4008     *            the separator character to use
    4009     * @return the joined String, {@code null} if null array input
    4010     * @since 3.2
    4011     */
    4012    public static String join(final byte[] array, final char separator) {
    4013        if (array == null) {
    4014            return null;
    4015        }
    4016        return join(array, separator, 0, array.length);
    4017    }
    4018
    4019    /**
    4020     * <p>
    4021     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4022     * </p>
    4023     *
    4024     * <p>
    4025     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4026     * by empty strings.
    4027     * </p>
    4028     *
    4029     * <pre>
    4030     * StringUtils.join(null, *)               = null
    4031     * StringUtils.join([], *)                 = ""
    4032     * StringUtils.join([null], *)             = ""
    4033     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4034     * StringUtils.join([1, 2, 3], null) = "123"
    4035     * </pre>
    4036     *
    4037     * @param array
    4038     *            the array of values to join together, may be null
    4039     * @param separator
    4040     *            the separator character to use
    4041     * @return the joined String, {@code null} if null array input
    4042     * @since 3.2
    4043     */
    4044    public static String join(final char[] array, final char separator) {
    4045        if (array == null) {
    4046            return null;
    4047        }
    4048        return join(array, separator, 0, array.length);
    4049    }
    4050
    4051    /**
    4052     * <p>
    4053     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4054     * </p>
    4055     *
    4056     * <p>
    4057     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4058     * by empty strings.
    4059     * </p>
    4060     *
    4061     * <pre>
    4062     * StringUtils.join(null, *)               = null
    4063     * StringUtils.join([], *)                 = ""
    4064     * StringUtils.join([null], *)             = ""
    4065     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4066     * StringUtils.join([1, 2, 3], null) = "123"
    4067     * </pre>
    4068     *
    4069     * @param array
    4070     *            the array of values to join together, may be null
    4071     * @param separator
    4072     *            the separator character to use
    4073     * @return the joined String, {@code null} if null array input
    4074     * @since 3.2
    4075     */
    4076    public static String join(final float[] array, final char separator) {
    4077        if (array == null) {
    4078            return null;
    4079        }
    4080        return join(array, separator, 0, array.length);
    4081    }
    4082
    4083    /**
    4084     * <p>
    4085     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4086     * </p>
    4087     *
    4088     * <p>
    4089     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4090     * by empty strings.
    4091     * </p>
    4092     *
    4093     * <pre>
    4094     * StringUtils.join(null, *)               = null
    4095     * StringUtils.join([], *)                 = ""
    4096     * StringUtils.join([null], *)             = ""
    4097     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4098     * StringUtils.join([1, 2, 3], null) = "123"
    4099     * </pre>
    4100     *
    4101     * @param array
    4102     *            the array of values to join together, may be null
    4103     * @param separator
    4104     *            the separator character to use
    4105     * @return the joined String, {@code null} if null array input
    4106     * @since 3.2
    4107     */
    4108    public static String join(final double[] array, final char separator) {
    4109        if (array == null) {
    4110            return null;
    4111        }
    4112        return join(array, separator, 0, array.length);
    4113    }
    4114
    4115
    4116    /**
    4117     * <p>Joins the elements of the provided array into a single String
    4118     * containing the provided list of elements.</p>
    4119     *
    4120     * <p>No delimiter is added before or after the list.
    4121     * Null objects or empty strings within the array are represented by
    4122     * empty strings.</p>
    4123     *
    4124     * <pre>
    4125     * StringUtils.join(null, *)               = null
    4126     * StringUtils.join([], *)                 = ""
    4127     * StringUtils.join([null], *)             = ""
    4128     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4129     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4130     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4131     * </pre>
    4132     *
    4133     * @param array  the array of values to join together, may be null
    4134     * @param separator  the separator character to use
    4135     * @param startIndex the first index to start joining from.  It is
    4136     * an error to pass in an end index past the end of the array
    4137     * @param endIndex the index to stop joining from (exclusive). It is
    4138     * an error to pass in an end index past the end of the array
    4139     * @return the joined String, {@code null} if null array input
    4140     * @since 2.0
    4141     */
    4142    public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
    4143        if (array == null) {
    4144            return null;
    4145        }
    4146        final int noOfItems = endIndex - startIndex;
    4147        if (noOfItems <= 0) {
    4148            return EMPTY;
    4149        }
    4150        final StringBuilder buf = newStringBuilder(noOfItems);
    4151        for (int i = startIndex; i < endIndex; i++) {
    4152            if (i > startIndex) {
    4153                buf.append(separator);
    4154            }
    4155            if (array[i] != null) {
    4156                buf.append(array[i]);
    4157            }
    4158        }
    4159        return buf.toString();
    4160    }
    4161
    4162    /**
    4163     * <p>
    4164     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4165     * </p>
    4166     *
    4167     * <p>
    4168     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4169     * by empty strings.
    4170     * </p>
    4171     *
    4172     * <pre>
    4173     * StringUtils.join(null, *)               = null
    4174     * StringUtils.join([], *)                 = ""
    4175     * StringUtils.join([null], *)             = ""
    4176     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4177     * StringUtils.join([1, 2, 3], null) = "123"
    4178     * </pre>
    4179     *
    4180     * @param array
    4181     *            the array of values to join together, may be null
    4182     * @param separator
    4183     *            the separator character to use
    4184     * @param startIndex
    4185     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4186     *            array
    4187     * @param endIndex
    4188     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4189     *            the array
    4190     * @return the joined String, {@code null} if null array input
    4191     * @since 3.2
    4192     */
    4193    public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
    4194        if (array == null) {
    4195            return null;
    4196        }
    4197        final int noOfItems = endIndex - startIndex;
    4198        if (noOfItems <= 0) {
    4199            return EMPTY;
    4200        }
    4201        final StringBuilder buf = newStringBuilder(noOfItems);
    4202        for (int i = startIndex; i < endIndex; i++) {
    4203            if (i > startIndex) {
    4204                buf.append(separator);
    4205            }
    4206            buf.append(array[i]);
    4207        }
    4208        return buf.toString();
    4209    }
    4210
    4211    /**
    4212     * <p>
    4213     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4214     * </p>
    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 separator
    4232     *            the separator character to use
    4233     * @param startIndex
    4234     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4235     *            array
    4236     * @param endIndex
    4237     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4238     *            the array
    4239     * @return the joined String, {@code null} if null array input
    4240     * @since 3.2
    4241     */
    4242    public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
    4243        if (array == null) {
    4244            return null;
    4245        }
    4246        final int noOfItems = endIndex - startIndex;
    4247        if (noOfItems <= 0) {
    4248            return EMPTY;
    4249        }
    4250        final StringBuilder buf = newStringBuilder(noOfItems);
    4251        for (int i = startIndex; i < endIndex; i++) {
    4252            if (i > startIndex) {
    4253                buf.append(separator);
    4254            }
    4255            buf.append(array[i]);
    4256        }
    4257        return buf.toString();
    4258    }
    4259
    4260    /**
    4261     * <p>
    4262     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4263     * </p>
    4264     *
    4265     * <p>
    4266     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4267     * by empty strings.
    4268     * </p>
    4269     *
    4270     * <pre>
    4271     * StringUtils.join(null, *)               = null
    4272     * StringUtils.join([], *)                 = ""
    4273     * StringUtils.join([null], *)             = ""
    4274     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4275     * StringUtils.join([1, 2, 3], null) = "123"
    4276     * </pre>
    4277     *
    4278     * @param array
    4279     *            the array of values to join together, may be null
    4280     * @param separator
    4281     *            the separator character to use
    4282     * @param startIndex
    4283     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4284     *            array
    4285     * @param endIndex
    4286     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4287     *            the array
    4288     * @return the joined String, {@code null} if null array input
    4289     * @since 3.2
    4290     */
    4291    public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
    4292        if (array == null) {
    4293            return null;
    4294        }
    4295        final int noOfItems = endIndex - startIndex;
    4296        if (noOfItems <= 0) {
    4297            return EMPTY;
    4298        }
    4299        final StringBuilder buf = newStringBuilder(noOfItems);
    4300        for (int i = startIndex; i < endIndex; i++) {
    4301            if (i > startIndex) {
    4302                buf.append(separator);
    4303            }
    4304            buf.append(array[i]);
    4305        }
    4306        return buf.toString();
    4307    }
    4308
    4309    /**
    4310     * <p>
    4311     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4312     * </p>
    4313     *
    4314     * <p>
    4315     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4316     * by empty strings.
    4317     * </p>
    4318     *
    4319     * <pre>
    4320     * StringUtils.join(null, *)               = null
    4321     * StringUtils.join([], *)                 = ""
    4322     * StringUtils.join([null], *)             = ""
    4323     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4324     * StringUtils.join([1, 2, 3], null) = "123"
    4325     * </pre>
    4326     *
    4327     * @param array
    4328     *            the array of values to join together, may be null
    4329     * @param separator
    4330     *            the separator character to use
    4331     * @param startIndex
    4332     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4333     *            array
    4334     * @param endIndex
    4335     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4336     *            the array
    4337     * @return the joined String, {@code null} if null array input
    4338     * @since 3.2
    4339     */
    4340    public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
    4341        if (array == null) {
    4342            return null;
    4343        }
    4344        final int noOfItems = endIndex - startIndex;
    4345        if (noOfItems <= 0) {
    4346            return EMPTY;
    4347        }
    4348        final StringBuilder buf = newStringBuilder(noOfItems);
    4349        for (int i = startIndex; i < endIndex; i++) {
    4350            if (i > startIndex) {
    4351                buf.append(separator);
    4352            }
    4353            buf.append(array[i]);
    4354        }
    4355        return buf.toString();
    4356    }
    4357
    4358    /**
    4359     * <p>
    4360     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4361     * </p>
    4362     *
    4363     * <p>
    4364     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4365     * by empty strings.
    4366     * </p>
    4367     *
    4368     * <pre>
    4369     * StringUtils.join(null, *)               = null
    4370     * StringUtils.join([], *)                 = ""
    4371     * StringUtils.join([null], *)             = ""
    4372     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4373     * StringUtils.join([1, 2, 3], null) = "123"
    4374     * </pre>
    4375     *
    4376     * @param array
    4377     *            the array of values to join together, may be null
    4378     * @param separator
    4379     *            the separator character to use
    4380     * @param startIndex
    4381     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4382     *            array
    4383     * @param endIndex
    4384     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4385     *            the array
    4386     * @return the joined String, {@code null} if null array input
    4387     * @since 3.2
    4388     */
    4389    public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
    4390        if (array == null) {
    4391            return null;
    4392        }
    4393        final int noOfItems = endIndex - startIndex;
    4394        if (noOfItems <= 0) {
    4395            return EMPTY;
    4396        }
    4397        final StringBuilder buf = newStringBuilder(noOfItems);
    4398        for (int i = startIndex; i < endIndex; i++) {
    4399            if (i > startIndex) {
    4400                buf.append(separator);
    4401            }
    4402            buf.append(array[i]);
    4403        }
    4404        return buf.toString();
    4405    }
    4406
    4407    /**
    4408     * <p>
    4409     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4410     * </p>
    4411     *
    4412     * <p>
    4413     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4414     * by empty strings.
    4415     * </p>
    4416     *
    4417     * <pre>
    4418     * StringUtils.join(null, *)               = null
    4419     * StringUtils.join([], *)                 = ""
    4420     * StringUtils.join([null], *)             = ""
    4421     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4422     * StringUtils.join([1, 2, 3], null) = "123"
    4423     * </pre>
    4424     *
    4425     * @param array
    4426     *            the array of values to join together, may be null
    4427     * @param separator
    4428     *            the separator character to use
    4429     * @param startIndex
    4430     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4431     *            array
    4432     * @param endIndex
    4433     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4434     *            the array
    4435     * @return the joined String, {@code null} if null array input
    4436     * @since 3.2
    4437     */
    4438    public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
    4439        if (array == null) {
    4440            return null;
    4441        }
    4442        final int noOfItems = endIndex - startIndex;
    4443        if (noOfItems <= 0) {
    4444            return EMPTY;
    4445        }
    4446        final StringBuilder buf = newStringBuilder(noOfItems);
    4447        for (int i = startIndex; i < endIndex; i++) {
    4448            if (i > startIndex) {
    4449                buf.append(separator);
    4450            }
    4451            buf.append(array[i]);
    4452        }
    4453        return buf.toString();
    4454    }
    4455
    4456    /**
    4457     * <p>
    4458     * Joins the elements of the provided array into a single String containing the provided list of elements.
    4459     * </p>
    4460     *
    4461     * <p>
    4462     * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
    4463     * by empty strings.
    4464     * </p>
    4465     *
    4466     * <pre>
    4467     * StringUtils.join(null, *)               = null
    4468     * StringUtils.join([], *)                 = ""
    4469     * StringUtils.join([null], *)             = ""
    4470     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
    4471     * StringUtils.join([1, 2, 3], null) = "123"
    4472     * </pre>
    4473     *
    4474     * @param array
    4475     *            the array of values to join together, may be null
    4476     * @param separator
    4477     *            the separator character to use
    4478     * @param startIndex
    4479     *            the first index to start joining from. It is an error to pass in an end index past the end of the
    4480     *            array
    4481     * @param endIndex
    4482     *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
    4483     *            the array
    4484     * @return the joined String, {@code null} if null array input
    4485     * @since 3.2
    4486     */
    4487    public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
    4488        if (array == null) {
    4489            return null;
    4490        }
    4491        final int noOfItems = endIndex - startIndex;
    4492        if (noOfItems <= 0) {
    4493            return EMPTY;
    4494        }
    4495        final StringBuilder buf = newStringBuilder(noOfItems);
    4496        for (int i = startIndex; i < endIndex; i++) {
    4497            if (i > startIndex) {
    4498                buf.append(separator);
    4499            }
    4500            buf.append(array[i]);
    4501        }
    4502        return buf.toString();
    4503    }
    4504
    4505
    4506    /**
    4507     * <p>Joins the elements of the provided array into a single String
    4508     * containing the provided list of elements.</p>
    4509     *
    4510     * <p>No delimiter is added before or after the list.
    4511     * A {@code null} separator is the same as an empty String ("").
    4512     * Null objects or empty strings within the array are represented by
    4513     * empty strings.</p>
    4514     *
    4515     * <pre>
    4516     * StringUtils.join(null, *)                = null
    4517     * StringUtils.join([], *)                  = ""
    4518     * StringUtils.join([null], *)              = ""
    4519     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    4520     * StringUtils.join(["a", "b", "c"], null)  = "abc"
    4521     * StringUtils.join(["a", "b", "c"], "")    = "abc"
    4522     * StringUtils.join([null, "", "a"], ',')   = ",,a"
    4523     * </pre>
    4524     *
    4525     * @param array  the array of values to join together, may be null
    4526     * @param separator  the separator character to use, null treated as ""
    4527     * @return the joined String, {@code null} if null array input
    4528     */
    4529    public static String join(final Object[] array, final String separator) {
    4530        if (array == null) {
    4531            return null;
    4532        }
    4533        return join(array, separator, 0, array.length);
    4534    }
    4535
    4536    /**
    4537     * <p>Joins the elements of the provided array into a single String
    4538     * containing the provided list of elements.</p>
    4539     *
    4540     * <p>No delimiter is added before or after the list.
    4541     * A {@code null} separator is the same as an empty String ("").
    4542     * Null objects or empty strings within the array are represented by
    4543     * empty strings.</p>
    4544     *
    4545     * <pre>
    4546     * StringUtils.join(null, *, *, *)                = null
    4547     * StringUtils.join([], *, *, *)                  = ""
    4548     * StringUtils.join([null], *, *, *)              = ""
    4549     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
    4550     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
    4551     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
    4552     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
    4553     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
    4554     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
    4555     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
    4556     * </pre>
    4557     *
    4558     * @param array  the array of values to join together, may be null
    4559     * @param separator  the separator character to use, null treated as ""
    4560     * @param startIndex the first index to start joining from.
    4561     * @param endIndex the index to stop joining from (exclusive).
    4562     * @return the joined String, {@code null} if null array input; or the empty string
    4563     * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
    4564     * {@code endIndex - startIndex}
    4565     * @throws ArrayIndexOutOfBoundsException ife<br>
    4566     * {@code startIndex < 0} or <br>
    4567     * {@code startIndex >= array.length()} or <br>
    4568     * {@code endIndex < 0} or <br>
    4569     * {@code endIndex > array.length()}
    4570     */
    4571    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
    4572        if (array == null) {
    4573            return null;
    4574        }
    4575        if (separator == null) {
    4576            separator = EMPTY;
    4577        }
    4578
    4579        // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
    4580        //           (Assuming that all Strings are roughly equally long)
    4581        final int noOfItems = endIndex - startIndex;
    4582        if (noOfItems <= 0) {
    4583            return EMPTY;
    4584        }
    4585
    4586        final StringBuilder buf = newStringBuilder(noOfItems);
    4587
    4588        for (int i = startIndex; i < endIndex; i++) {
    4589            if (i > startIndex) {
    4590                buf.append(separator);
    4591            }
    4592            if (array[i] != null) {
    4593                buf.append(array[i]);
    4594            }
    4595        }
    4596        return buf.toString();
    4597    }
    4598
    4599    /**
    4600     * <p>Joins the elements of the provided {@code Iterator} into
    4601     * a single String containing the provided elements.</p>
    4602     *
    4603     * <p>No delimiter is added before or after the list. Null objects or empty
    4604     * strings within the iteration are represented by empty strings.</p>
    4605     *
    4606     * <p>See the examples here: {@link #join(Object[],char)}. </p>
    4607     *
    4608     * @param iterator  the {@code Iterator} of values to join together, may be null
    4609     * @param separator  the separator character to use
    4610     * @return the joined String, {@code null} if null iterator input
    4611     * @since 2.0
    4612     */
    4613    public static String join(final Iterator<?> iterator, final char separator) {
    4614
    4615        // handle null, zero and one elements before building a buffer
    4616        if (iterator == null) {
    4617            return null;
    4618        }
    4619        if (!iterator.hasNext()) {
    4620            return EMPTY;
    4621        }
    4622        final Object first = iterator.next();
    4623        if (!iterator.hasNext()) {
    4624            return Objects.toString(first, EMPTY);
    4625        }
    4626
    4627        // two or more elements
    4628        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
    4629        if (first != null) {
    4630            buf.append(first);
    4631        }
    4632
    4633        while (iterator.hasNext()) {
    4634            buf.append(separator);
    4635            final Object obj = iterator.next();
    4636            if (obj != null) {
    4637                buf.append(obj);
    4638            }
    4639        }
    4640
    4641        return buf.toString();
    4642    }
    4643
    4644    /**
    4645     * <p>Joins the elements of the provided {@code Iterator} into
    4646     * a single String containing the provided elements.</p>
    4647     *
    4648     * <p>No delimiter is added before or after the list.
    4649     * A {@code null} separator is the same as an empty String ("").</p>
    4650     *
    4651     * <p>See the examples here: {@link #join(Object[],String)}. </p>
    4652     *
    4653     * @param iterator  the {@code Iterator} of values to join together, may be null
    4654     * @param separator  the separator character to use, null treated as ""
    4655     * @return the joined String, {@code null} if null iterator input
    4656     */
    4657    public static String join(final Iterator<?> iterator, final String separator) {
    4658
    4659        // handle null, zero and one elements before building a buffer
    4660        if (iterator == null) {
    4661            return null;
    4662        }
    4663        if (!iterator.hasNext()) {
    4664            return EMPTY;
    4665        }
    4666        final Object first = iterator.next();
    4667        if (!iterator.hasNext()) {
    4668            return Objects.toString(first, "");
    4669        }
    4670
    4671        // two or more elements
    4672        final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small
    4673        if (first != null) {
    4674            buf.append(first);
    4675        }
    4676
    4677        while (iterator.hasNext()) {
    4678            if (separator != null) {
    4679                buf.append(separator);
    4680            }
    4681            final Object obj = iterator.next();
    4682            if (obj != null) {
    4683                buf.append(obj);
    4684            }
    4685        }
    4686        return buf.toString();
    4687    }
    4688
    4689    /**
    4690     * <p>Joins the elements of the provided {@code Iterable} into
    4691     * a single String containing the provided elements.</p>
    4692     *
    4693     * <p>No delimiter is added before or after the list. Null objects or empty
    4694     * strings within the iteration are represented by empty strings.</p>
    4695     *
    4696     * <p>See the examples here: {@link #join(Object[],char)}. </p>
    4697     *
    4698     * @param iterable  the {@code Iterable} providing the values to join together, may be null
    4699     * @param separator  the separator character to use
    4700     * @return the joined String, {@code null} if null iterator input
    4701     * @since 2.3
    4702     */
    4703    public static String join(final Iterable<?> iterable, final char separator) {
    4704        if (iterable == null) {
    4705            return null;
    4706        }
    4707        return join(iterable.iterator(), separator);
    4708    }
    4709
    4710    /**
    4711     * <p>Joins the elements of the provided {@code Iterable} into
    4712     * a single String containing the provided elements.</p>
    4713     *
    4714     * <p>No delimiter is added before or after the list.
    4715     * A {@code null} separator is the same as an empty String ("").</p>
    4716     *
    4717     * <p>See the examples here: {@link #join(Object[],String)}. </p>
    4718     *
    4719     * @param iterable  the {@code Iterable} providing the values to join together, may be null
    4720     * @param separator  the separator character to use, null treated as ""
    4721     * @return the joined String, {@code null} if null iterator input
    4722     * @since 2.3
    4723     */
    4724    public static String join(final Iterable<?> iterable, final String separator) {
    4725        if (iterable == null) {
    4726            return null;
    4727        }
    4728        return join(iterable.iterator(), separator);
    4729    }
    4730
    4731    /**
    4732     * <p>Joins the elements of the provided {@code List} into a single String
    4733     * containing the provided list of elements.</p>
    4734     *
    4735     * <p>No delimiter is added before or after the list.
    4736     * Null objects or empty strings within the array are represented by
    4737     * empty strings.</p>
    4738     *
    4739     * <pre>
    4740     * StringUtils.join(null, *)               = null
    4741     * StringUtils.join([], *)                 = ""
    4742     * StringUtils.join([null], *)             = ""
    4743     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4744     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4745     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4746     * </pre>
    4747     *
    4748     * @param list  the {@code List} of values to join together, may be null
    4749     * @param separator  the separator character to use
    4750     * @param startIndex the first index to start joining from.  It is
    4751     * an error to pass in an end index past the end of the list
    4752     * @param endIndex the index to stop joining from (exclusive). It is
    4753     * an error to pass in an end index past the end of the list
    4754     * @return the joined String, {@code null} if null list input
    4755     * @since 3.8
    4756     */
    4757    public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
    4758        if (list == null) {
    4759            return null;
    4760        }
    4761        final int noOfItems = endIndex - startIndex;
    4762        if (noOfItems <= 0) {
    4763            return EMPTY;
    4764        }
    4765        final List<?> subList = list.subList(startIndex, endIndex);
    4766        return join(subList.iterator(), separator);
    4767    }
    4768
    4769    /**
    4770     * <p>Joins the elements of the provided {@code List} into a single String
    4771     * containing the provided list of elements.</p>
    4772     *
    4773     * <p>No delimiter is added before or after the list.
    4774     * Null objects or empty strings within the array are represented by
    4775     * empty strings.</p>
    4776     *
    4777     * <pre>
    4778     * StringUtils.join(null, *)               = null
    4779     * StringUtils.join([], *)                 = ""
    4780     * StringUtils.join([null], *)             = ""
    4781     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    4782     * StringUtils.join(["a", "b", "c"], null) = "abc"
    4783     * StringUtils.join([null, "", "a"], ';')  = ";;a"
    4784     * </pre>
    4785     *
    4786     * @param list  the {@code List} of values to join together, may be null
    4787     * @param separator  the separator character to use
    4788     * @param startIndex the first index to start joining from.  It is
    4789     * an error to pass in an end index past the end of the list
    4790     * @param endIndex the index to stop joining from (exclusive). It is
    4791     * an error to pass in an end index past the end of the list
    4792     * @return the joined String, {@code null} if null list input
    4793     * @since 3.8
    4794     */
    4795    public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
    4796        if (list == null) {
    4797            return null;
    4798        }
    4799        final int noOfItems = endIndex - startIndex;
    4800        if (noOfItems <= 0) {
    4801            return EMPTY;
    4802        }
    4803        final List<?> subList = list.subList(startIndex, endIndex);
    4804        return join(subList.iterator(), separator);
    4805    }
    4806
    4807    /**
    4808     * <p>Joins the elements of the provided varargs into a
    4809     * single String containing the provided elements.</p>
    4810     *
    4811     * <p>No delimiter is added before or after the list.
    4812     * {@code null} elements and separator are treated as empty Strings ("").</p>
    4813     *
    4814     * <pre>
    4815     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
    4816     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
    4817     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
    4818     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
    4819     * </pre>
    4820     *
    4821     * @param separator the separator character to use, null treated as ""
    4822     * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
    4823     * @return the joined String.
    4824     * @throws java.lang.IllegalArgumentException if a null varargs is provided
    4825     * @since 3.5
    4826     */
    4827    public static String joinWith(final String separator, final Object... objects) {
    4828        if (objects == null) {
    4829            throw new IllegalArgumentException("Object varargs must not be null");
    4830        }
    4831
    4832        final String sanitizedSeparator = defaultString(separator);
    4833
    4834        final StringBuilder result = new StringBuilder();
    4835
    4836        final Iterator<Object> iterator = Arrays.asList(objects).iterator();
    4837        while (iterator.hasNext()) {
    4838            final String value = Objects.toString(iterator.next(), "");
    4839            result.append(value);
    4840
    4841            if (iterator.hasNext()) {
    4842                result.append(sanitizedSeparator);
    4843            }
    4844        }
    4845
    4846        return result.toString();
    4847    }
    4848
    4849    // Delete
    4850    //-----------------------------------------------------------------------
    4851    /**
    4852     * <p>Deletes all whitespaces from a String as defined by
    4853     * {@link Character#isWhitespace(char)}.</p>
    4854     *
    4855     * <pre>
    4856     * StringUtils.deleteWhitespace(null)         = null
    4857     * StringUtils.deleteWhitespace("")           = ""
    4858     * StringUtils.deleteWhitespace("abc")        = "abc"
    4859     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    4860     * </pre>
    4861     *
    4862     * @param str  the String to delete whitespace from, may be null
    4863     * @return the String without whitespaces, {@code null} if null String input
    4864     */
    4865    public static String deleteWhitespace(final String str) {
    4866        if (isEmpty(str)) {
    4867            return str;
    4868        }
    4869        final int sz = str.length();
    4870        final char[] chs = new char[sz];
    4871        int count = 0;
    4872        for (int i = 0; i < sz; i++) {
    4873            if (!Character.isWhitespace(str.charAt(i))) {
    4874                chs[count++] = str.charAt(i);
    4875            }
    4876        }
    4877        if (count == sz) {
    4878            return str;
    4879        }
    4880        return new String(chs, 0, count);
    4881    }
    4882
    4883    // Remove
    4884    //-----------------------------------------------------------------------
    4885    /**
    4886     * <p>Removes a substring only if it is at the beginning of a source string,
    4887     * otherwise returns the source string.</p>
    4888     *
    4889     * <p>A {@code null} source string will return {@code null}.
    4890     * An empty ("") source string will return the empty string.
    4891     * A {@code null} search string will return the source string.</p>
    4892     *
    4893     * <pre>
    4894     * StringUtils.removeStart(null, *)      = null
    4895     * StringUtils.removeStart("", *)        = ""
    4896     * StringUtils.removeStart(*, null)      = *
    4897     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    4898     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    4899     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    4900     * StringUtils.removeStart("abc", "")    = "abc"
    4901     * </pre>
    4902     *
    4903     * @param str  the source String to search, may be null
    4904     * @param remove  the String to search for and remove, may be null
    4905     * @return the substring with the string removed if found,
    4906     *  {@code null} if null String input
    4907     * @since 2.1
    4908     */
    4909    public static String removeStart(final String str, final String remove) {
    4910        if (isEmpty(str) || isEmpty(remove)) {
    4911            return str;
    4912        }
    4913        if (str.startsWith(remove)){
    4914            return str.substring(remove.length());
    4915        }
    4916        return str;
    4917    }
    4918
    4919    /**
    4920     * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
    4921     * otherwise returns the source string.</p>
    4922     *
    4923     * <p>A {@code null} source string will return {@code null}.
    4924     * An empty ("") source string will return the empty string.
    4925     * A {@code null} search string will return the source string.</p>
    4926     *
    4927     * <pre>
    4928     * StringUtils.removeStartIgnoreCase(null, *)      = null
    4929     * StringUtils.removeStartIgnoreCase("", *)        = ""
    4930     * StringUtils.removeStartIgnoreCase(*, null)      = *
    4931     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
    4932     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
    4933     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
    4934     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    4935     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
    4936     * </pre>
    4937     *
    4938     * @param str  the source String to search, may be null
    4939     * @param remove  the String to search for (case insensitive) and remove, may be null
    4940     * @return the substring with the string removed if found,
    4941     *  {@code null} if null String input
    4942     * @since 2.4
    4943     */
    4944    public static String removeStartIgnoreCase(final String str, final String remove) {
    4945        if (isEmpty(str) || isEmpty(remove)) {
    4946            return str;
    4947        }
    4948        if (startsWithIgnoreCase(str, remove)) {
    4949            return str.substring(remove.length());
    4950        }
    4951        return str;
    4952    }
    4953
    4954    /**
    4955     * <p>Removes a substring only if it is at the end of a source string,
    4956     * otherwise returns the source string.</p>
    4957     *
    4958     * <p>A {@code null} source string will return {@code null}.
    4959     * An empty ("") source string will return the empty string.
    4960     * A {@code null} search string will return the source string.</p>
    4961     *
    4962     * <pre>
    4963     * StringUtils.removeEnd(null, *)      = null
    4964     * StringUtils.removeEnd("", *)        = ""
    4965     * StringUtils.removeEnd(*, null)      = *
    4966     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    4967     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    4968     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    4969     * StringUtils.removeEnd("abc", "")    = "abc"
    4970     * </pre>
    4971     *
    4972     * @param str  the source String to search, may be null
    4973     * @param remove  the String to search for and remove, may be null
    4974     * @return the substring with the string removed if found,
    4975     *  {@code null} if null String input
    4976     * @since 2.1
    4977     */
    4978    public static String removeEnd(final String str, final String remove) {
    4979        if (isEmpty(str) || isEmpty(remove)) {
    4980            return str;
    4981        }
    4982        if (str.endsWith(remove)) {
    4983            return str.substring(0, str.length() - remove.length());
    4984        }
    4985        return str;
    4986    }
    4987
    4988    /**
    4989     * <p>Case insensitive removal of a substring if it is at the end of a source string,
    4990     * otherwise returns the source string.</p>
    4991     *
    4992     * <p>A {@code null} source string will return {@code null}.
    4993     * An empty ("") source string will return the empty string.
    4994     * A {@code null} search string will return the source string.</p>
    4995     *
    4996     * <pre>
    4997     * StringUtils.removeEndIgnoreCase(null, *)      = null
    4998     * StringUtils.removeEndIgnoreCase("", *)        = ""
    4999     * StringUtils.removeEndIgnoreCase(*, null)      = *
    5000     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    5001     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    5002     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    5003     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    5004     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    5005     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    5006     * </pre>
    5007     *
    5008     * @param str  the source String to search, may be null
    5009     * @param remove  the String to search for (case insensitive) and remove, may be null
    5010     * @return the substring with the string removed if found,
    5011     *  {@code null} if null String input
    5012     * @since 2.4
    5013     */
    5014    public static String removeEndIgnoreCase(final String str, final String remove) {
    5015        if (isEmpty(str) || isEmpty(remove)) {
    5016            return str;
    5017        }
    5018        if (endsWithIgnoreCase(str, remove)) {
    5019            return str.substring(0, str.length() - remove.length());
    5020        }
    5021        return str;
    5022    }
    5023
    5024    /**
    5025     * <p>Removes all occurrences of a substring from within the source string.</p>
    5026     *
    5027     * <p>A {@code null} source string will return {@code null}.
    5028     * An empty ("") source string will return the empty string.
    5029     * A {@code null} remove string will return the source string.
    5030     * An empty ("") remove string will return the source string.</p>
    5031     *
    5032     * <pre>
    5033     * StringUtils.remove(null, *)        = null
    5034     * StringUtils.remove("", *)          = ""
    5035     * StringUtils.remove(*, null)        = *
    5036     * StringUtils.remove(*, "")          = *
    5037     * StringUtils.remove("queued", "ue") = "qd"
    5038     * StringUtils.remove("queued", "zz") = "queued"
    5039     * </pre>
    5040     *
    5041     * @param str  the source String to search, may be null
    5042     * @param remove  the String to search for and remove, may be null
    5043     * @return the substring with the string removed if found,
    5044     *  {@code null} if null String input
    5045     * @since 2.1
    5046     */
    5047    public static String remove(final String str, final String remove) {
    5048        if (isEmpty(str) || isEmpty(remove)) {
    5049            return str;
    5050        }
    5051        return replace(str, remove, EMPTY, -1);
    5052    }
    5053
    5054    /**
    5055     * <p>
    5056     * Case insensitive removal of all occurrences of a substring from within
    5057     * the source string.
    5058     * </p>
    5059     *
    5060     * <p>
    5061     * A {@code null} source string will return {@code null}. An empty ("")
    5062     * source string will return the empty string. A {@code null} remove string
    5063     * will return the source string. An empty ("") remove string will return
    5064     * the source string.
    5065     * </p>
    5066     *
    5067     * <pre>
    5068     * StringUtils.removeIgnoreCase(null, *)        = null
    5069     * StringUtils.removeIgnoreCase("", *)          = ""
    5070     * StringUtils.removeIgnoreCase(*, null)        = *
    5071     * StringUtils.removeIgnoreCase(*, "")          = *
    5072     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
    5073     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
    5074     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
    5075     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
    5076     * </pre>
    5077     *
    5078     * @param str
    5079     *            the source String to search, may be null
    5080     * @param remove
    5081     *            the String to search for (case insensitive) and remove, may be
    5082     *            null
    5083     * @return the substring with the string removed if found, {@code null} if
    5084     *         null String input
    5085     * @since 3.5
    5086     */
    5087    public static String removeIgnoreCase(final String str, final String remove) {
    5088        if (isEmpty(str) || isEmpty(remove)) {
    5089            return str;
    5090        }
    5091        return replaceIgnoreCase(str, remove, EMPTY, -1);
    5092    }
    5093
    5094    /**
    5095     * <p>Removes all occurrences of a character from within the source string.</p>
    5096     *
    5097     * <p>A {@code null} source string will return {@code null}.
    5098     * An empty ("") source string will return the empty string.</p>
    5099     *
    5100     * <pre>
    5101     * StringUtils.remove(null, *)       = null
    5102     * StringUtils.remove("", *)         = ""
    5103     * StringUtils.remove("queued", 'u') = "qeed"
    5104     * StringUtils.remove("queued", 'z') = "queued"
    5105     * </pre>
    5106     *
    5107     * @param str  the source String to search, may be null
    5108     * @param remove  the char to search for and remove, may be null
    5109     * @return the substring with the char removed if found,
    5110     *  {@code null} if null String input
    5111     * @since 2.1
    5112     */
    5113    public static String remove(final String str, final char remove) {
    5114        if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    5115            return str;
    5116        }
    5117        final char[] chars = str.toCharArray();
    5118        int pos = 0;
    5119        for (int i = 0; i < chars.length; i++) {
    5120            if (chars[i] != remove) {
    5121                chars[pos++] = chars[i];
    5122            }
    5123        }
    5124        return new String(chars, 0, pos);
    5125    }
    5126
    5127    /**
    5128     * <p>Removes each substring of the text String that matches the given regular expression.</p>
    5129     *
    5130     * This method is a {@code null} safe equivalent to:
    5131     * <ul>
    5132     *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
    5133     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
    5134     * </ul>
    5135     *
    5136     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5137     *
    5138     * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
    5139     * is NOT automatically added.
    5140     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
    5141     * DOTALL is also known as single-line mode in Perl.</p>
    5142     *
    5143     * <pre>
    5144     * StringUtils.removeAll(null, *)      = null
    5145     * StringUtils.removeAll("any", (String) null)  = "any"
    5146     * StringUtils.removeAll("any", "")    = "any"
    5147     * StringUtils.removeAll("any", ".*")  = ""
    5148     * StringUtils.removeAll("any", ".+")  = ""
    5149     * StringUtils.removeAll("abc", ".?")  = ""
    5150     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
    5151     * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    5152     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
    5153     * </pre>
    5154     *
    5155     * @param text  text to remove from, may be null
    5156     * @param regex  the regular expression to which this string is to be matched
    5157     * @return  the text with any removes processed,
    5158     *              {@code null} if null String input
    5159     *
    5160     * @throws  java.util.regex.PatternSyntaxException
    5161     *              if the regular expression's syntax is invalid
    5162     *
    5163     * @see #replaceAll(String, String, String)
    5164     * @see #removePattern(String, String)
    5165     * @see String#replaceAll(String, String)
    5166     * @see java.util.regex.Pattern
    5167     * @see java.util.regex.Pattern#DOTALL
    5168     * @since 3.5
    5169     *
    5170     * @deprecated Moved to RegExUtils.
    5171     */
    5172    @Deprecated
    5173    public static String removeAll(final String text, final String regex) {
    5174        return RegExUtils.removeAll(text, regex);
    5175    }
    5176
    5177    /**
    5178     * <p>Removes the first substring of the text string that matches the given regular expression.</p>
    5179     *
    5180     * This method is a {@code null} safe equivalent to:
    5181     * <ul>
    5182     *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
    5183     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
    5184     * </ul>
    5185     *
    5186     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5187     *
    5188     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    5189     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
    5190     * DOTALL is also known as single-line mode in Perl.</p>
    5191     *
    5192     * <pre>
    5193     * StringUtils.removeFirst(null, *)      = null
    5194     * StringUtils.removeFirst("any", (String) null)  = "any"
    5195     * StringUtils.removeFirst("any", "")    = "any"
    5196     * StringUtils.removeFirst("any", ".*")  = ""
    5197     * StringUtils.removeFirst("any", ".+")  = ""
    5198     * StringUtils.removeFirst("abc", ".?")  = "bc"
    5199     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
    5200     * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
    5201     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
    5202     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
    5203     * </pre>
    5204     *
    5205     * @param text  text to remove from, may be null
    5206     * @param regex  the regular expression to which this string is to be matched
    5207     * @return  the text with the first replacement processed,
    5208     *              {@code null} if null String input
    5209     *
    5210     * @throws  java.util.regex.PatternSyntaxException
    5211     *              if the regular expression's syntax is invalid
    5212     *
    5213     * @see #replaceFirst(String, String, String)
    5214     * @see String#replaceFirst(String, String)
    5215     * @see java.util.regex.Pattern
    5216     * @see java.util.regex.Pattern#DOTALL
    5217     * @since 3.5
    5218     *
    5219     * @deprecated Moved to RegExUtils.
    5220     */
    5221    @Deprecated
    5222    public static String removeFirst(final String text, final String regex) {
    5223        return replaceFirst(text, regex, EMPTY);
    5224    }
    5225
    5226    // Replacing
    5227    //-----------------------------------------------------------------------
    5228    /**
    5229     * <p>Replaces a String with another String inside a larger String, once.</p>
    5230     *
    5231     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5232     *
    5233     * <pre>
    5234     * StringUtils.replaceOnce(null, *, *)        = null
    5235     * StringUtils.replaceOnce("", *, *)          = ""
    5236     * StringUtils.replaceOnce("any", null, *)    = "any"
    5237     * StringUtils.replaceOnce("any", *, null)    = "any"
    5238     * StringUtils.replaceOnce("any", "", *)      = "any"
    5239     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    5240     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    5241     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    5242     * </pre>
    5243     *
    5244     * @see #replace(String text, String searchString, String replacement, int max)
    5245     * @param text  text to search and replace in, may be null
    5246     * @param searchString  the String to search for, may be null
    5247     * @param replacement  the String to replace with, may be null
    5248     * @return the text with any replacements processed,
    5249     *  {@code null} if null String input
    5250     */
    5251    public static String replaceOnce(final String text, final String searchString, final String replacement) {
    5252        return replace(text, searchString, replacement, 1);
    5253    }
    5254
    5255    /**
    5256     * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
    5257     *
    5258     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5259     *
    5260     * <pre>
    5261     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
    5262     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
    5263     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
    5264     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
    5265     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
    5266     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
    5267     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
    5268     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
    5269     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
    5270     * </pre>
    5271     *
    5272     * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    5273     * @param text  text to search and replace in, may be null
    5274     * @param searchString  the String to search for (case insensitive), may be null
    5275     * @param replacement  the String to replace with, may be null
    5276     * @return the text with any replacements processed,
    5277     *  {@code null} if null String input
    5278     * @since 3.5
    5279     */
    5280    public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
    5281        return replaceIgnoreCase(text, searchString, replacement, 1);
    5282    }
    5283
    5284    /**
    5285     * <p>Replaces each substring of the source String that matches the given regular expression with the given
    5286     * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.</p>
    5287     *
    5288     * This call is a {@code null} safe equivalent to:
    5289     * <ul>
    5290     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
    5291     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
    5292     * </ul>
    5293     *
    5294     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5295     *
    5296     * <pre>
    5297     * StringUtils.replacePattern(null, *, *)       = null
    5298     * StringUtils.replacePattern("any", (String) null, *)   = "any"
    5299     * StringUtils.replacePattern("any", *, null)   = "any"
    5300     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
    5301     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
    5302     * StringUtils.replacePattern("", ".+", "zzz")  = ""
    5303     * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
    5304     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
    5305     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    5306     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    5307     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    5308     * </pre>
    5309     *
    5310     * @param source
    5311     *            the source string
    5312     * @param regex
    5313     *            the regular expression to which this string is to be matched
    5314     * @param replacement
    5315     *            the string to be substituted for each match
    5316     * @return The resulting {@code String}
    5317     * @see #replaceAll(String, String, String)
    5318     * @see String#replaceAll(String, String)
    5319     * @see Pattern#DOTALL
    5320     * @since 3.2
    5321     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    5322     *
    5323     * @deprecated Moved to RegExUtils.
    5324     */
    5325    @Deprecated
    5326    public static String replacePattern(final String source, final String regex, final String replacement) {
    5327        return RegExUtils.replacePattern(source, regex, replacement);
    5328    }
    5329
    5330    /**
    5331     * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
    5332     * </p>
    5333     *
    5334     * This call is a {@code null} safe equivalent to:
    5335     * <ul>
    5336     * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
    5337     * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
    5338     * </ul>
    5339     *
    5340     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5341     *
    5342     * <pre>
    5343     * StringUtils.removePattern(null, *)       = null
    5344     * StringUtils.removePattern("any", (String) null)   = "any"
    5345     * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
    5346     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
    5347     * </pre>
    5348     *
    5349     * @param source
    5350     *            the source string
    5351     * @param regex
    5352     *            the regular expression to which this string is to be matched
    5353     * @return The resulting {@code String}
    5354     * @see #replacePattern(String, String, String)
    5355     * @see String#replaceAll(String, String)
    5356     * @see Pattern#DOTALL
    5357     * @since 3.2
    5358     * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
    5359     *
    5360     * @deprecated Moved to RegExUtils.
    5361     */
    5362    @Deprecated
    5363    public static String removePattern(final String source, final String regex) {
    5364        return RegExUtils.removePattern(source, regex);
    5365    }
    5366
    5367    /**
    5368     * <p>Replaces each substring of the text String that matches the given regular expression
    5369     * with the given replacement.</p>
    5370     *
    5371     * This method is a {@code null} safe equivalent to:
    5372     * <ul>
    5373     *  <li>{@code text.replaceAll(regex, replacement)}</li>
    5374     *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
    5375     * </ul>
    5376     *
    5377     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5378     *
    5379     * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
    5380     * is NOT automatically added.
    5381     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
    5382     * DOTALL is also known as single-line mode in Perl.</p>
    5383     *
    5384     * <pre>
    5385     * StringUtils.replaceAll(null, *, *)       = null
    5386     * StringUtils.replaceAll("any", (String) null, *)   = "any"
    5387     * StringUtils.replaceAll("any", *, null)   = "any"
    5388     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
    5389     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
    5390     * StringUtils.replaceAll("", ".+", "zzz")  = ""
    5391     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
    5392     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
    5393     * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    5394     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
    5395     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
    5396     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
    5397     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
    5398     * </pre>
    5399     *
    5400     * @param text  text to search and replace in, may be null
    5401     * @param regex  the regular expression to which this string is to be matched
    5402     * @param replacement  the string to be substituted for each match
    5403     * @return  the text with any replacements processed,
    5404     *              {@code null} if null String input
    5405     *
    5406     * @throws  java.util.regex.PatternSyntaxException
    5407     *              if the regular expression's syntax is invalid
    5408     *
    5409     * @see #replacePattern(String, String, String)
    5410     * @see String#replaceAll(String, String)
    5411     * @see java.util.regex.Pattern
    5412     * @see java.util.regex.Pattern#DOTALL
    5413     * @since 3.5
    5414     *
    5415     * @deprecated Moved to RegExUtils.
    5416     */
    5417    @Deprecated
    5418    public static String replaceAll(final String text, final String regex, final String replacement) {
    5419        return RegExUtils.replaceAll(text, regex, replacement);
    5420    }
    5421
    5422    /**
    5423     * <p>Replaces the first substring of the text string that matches the given regular expression
    5424     * with the given replacement.</p>
    5425     *
    5426     * This method is a {@code null} safe equivalent to:
    5427     * <ul>
    5428     *  <li>{@code text.replaceFirst(regex, replacement)}</li>
    5429     *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
    5430     * </ul>
    5431     *
    5432     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5433     *
    5434     * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
    5435     * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
    5436     * DOTALL is also known as single-line mode in Perl.</p>
    5437     *
    5438     * <pre>
    5439     * StringUtils.replaceFirst(null, *, *)       = null
    5440     * StringUtils.replaceFirst("any", (String) null, *)   = "any"
    5441     * StringUtils.replaceFirst("any", *, null)   = "any"
    5442     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
    5443     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
    5444     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
    5445     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
    5446     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
    5447     * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
    5448     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
    5449     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
    5450     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
    5451     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
    5452     * </pre>
    5453     *
    5454     * @param text  text to search and replace in, may be null
    5455     * @param regex  the regular expression to which this string is to be matched
    5456     * @param replacement  the string to be substituted for the first match
    5457     * @return  the text with the first replacement processed,
    5458     *              {@code null} if null String input
    5459     *
    5460     * @throws  java.util.regex.PatternSyntaxException
    5461     *              if the regular expression's syntax is invalid
    5462     *
    5463     * @see String#replaceFirst(String, String)
    5464     * @see java.util.regex.Pattern
    5465     * @see java.util.regex.Pattern#DOTALL
    5466     * @since 3.5
    5467     *
    5468     * @deprecated Moved to RegExUtils.
    5469     */
    5470    @Deprecated
    5471    public static String replaceFirst(final String text, final String regex, final String replacement) {
    5472        return RegExUtils.replaceFirst(text, regex, replacement);
    5473    }
    5474
    5475    /**
    5476     * <p>Replaces all occurrences of a String within another String.</p>
    5477     *
    5478     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5479     *
    5480     * <pre>
    5481     * StringUtils.replace(null, *, *)        = null
    5482     * StringUtils.replace("", *, *)          = ""
    5483     * StringUtils.replace("any", null, *)    = "any"
    5484     * StringUtils.replace("any", *, null)    = "any"
    5485     * StringUtils.replace("any", "", *)      = "any"
    5486     * StringUtils.replace("aba", "a", null)  = "aba"
    5487     * StringUtils.replace("aba", "a", "")    = "b"
    5488     * StringUtils.replace("aba", "a", "z")   = "zbz"
    5489     * </pre>
    5490     *
    5491     * @see #replace(String text, String searchString, String replacement, int max)
    5492     * @param text  text to search and replace in, may be null
    5493     * @param searchString  the String to search for, may be null
    5494     * @param replacement  the String to replace it with, may be null
    5495     * @return the text with any replacements processed,
    5496     *  {@code null} if null String input
    5497     */
    5498    public static String replace(final String text, final String searchString, final String replacement) {
    5499        return replace(text, searchString, replacement, -1);
    5500    }
    5501
    5502    /**
    5503    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
    5504    *
    5505    * <p>A {@code null} reference passed to this method is a no-op.</p>
    5506    *
    5507    * <pre>
    5508    * StringUtils.replaceIgnoreCase(null, *, *)        = null
    5509    * StringUtils.replaceIgnoreCase("", *, *)          = ""
    5510    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
    5511    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
    5512    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
    5513    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
    5514    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
    5515    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
    5516    * </pre>
    5517    *
    5518    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
    5519    * @param text  text to search and replace in, may be null
    5520    * @param searchString  the String to search for (case insensitive), may be null
    5521    * @param replacement  the String to replace it with, may be null
    5522    * @return the text with any replacements processed,
    5523    *  {@code null} if null String input
    5524    * @since 3.5
    5525    */
    5526   public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
    5527       return replaceIgnoreCase(text, searchString, replacement, -1);
    5528   }
    5529
    5530    /**
    5531     * <p>Replaces a String with another String inside a larger String,
    5532     * for the first {@code max} values of the search String.</p>
    5533     *
    5534     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5535     *
    5536     * <pre>
    5537     * StringUtils.replace(null, *, *, *)         = null
    5538     * StringUtils.replace("", *, *, *)           = ""
    5539     * StringUtils.replace("any", null, *, *)     = "any"
    5540     * StringUtils.replace("any", *, null, *)     = "any"
    5541     * StringUtils.replace("any", "", *, *)       = "any"
    5542     * StringUtils.replace("any", *, *, 0)        = "any"
    5543     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    5544     * StringUtils.replace("abaa", "a", "", -1)   = "b"
    5545     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    5546     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    5547     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    5548     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    5549     * </pre>
    5550     *
    5551     * @param text  text to search and replace in, may be null
    5552     * @param searchString  the String to search for, may be null
    5553     * @param replacement  the String to replace it with, may be null
    5554     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    5555     * @return the text with any replacements processed,
    5556     *  {@code null} if null String input
    5557     */
    5558    public static String replace(final String text, final String searchString, final String replacement, final int max) {
    5559        return replace(text, searchString, replacement, max, false);
    5560    }
    5561
    5562    /**
    5563     * <p>Replaces a String with another String inside a larger String,
    5564     * for the first {@code max} values of the search String,
    5565     * case sensitively/insensisitively based on {@code ignoreCase} value.</p>
    5566     *
    5567     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5568     *
    5569     * <pre>
    5570     * StringUtils.replace(null, *, *, *, false)         = null
    5571     * StringUtils.replace("", *, *, *, false)           = ""
    5572     * StringUtils.replace("any", null, *, *, false)     = "any"
    5573     * StringUtils.replace("any", *, null, *, false)     = "any"
    5574     * StringUtils.replace("any", "", *, *, false)       = "any"
    5575     * StringUtils.replace("any", *, *, 0, false)        = "any"
    5576     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
    5577     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
    5578     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
    5579     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
    5580     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
    5581     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
    5582     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
    5583     * </pre>
    5584     *
    5585     * @param text  text to search and replace in, may be null
    5586     * @param searchString  the String to search for (case insensitive), may be null
    5587     * @param replacement  the String to replace it with, may be null
    5588     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    5589     * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
    5590     * @return the text with any replacements processed,
    5591     *  {@code null} if null String input
    5592     */
    5593     private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
    5594         if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
    5595             return text;
    5596         }
    5597         String searchText = text;
    5598         if (ignoreCase) {
    5599             searchText = text.toLowerCase();
    5600             searchString = searchString.toLowerCase();
    5601         }
    5602         int start = 0;
    5603         int end = searchText.indexOf(searchString, start);
    5604         if (end == INDEX_NOT_FOUND) {
    5605             return text;
    5606         }
    5607         final int replLength = searchString.length();
    5608         int increase = replacement.length() - replLength;
    5609         increase = increase < 0 ? 0 : increase;
    5610         increase *= max < 0 ? 16 : max > 64 ? 64 : max;
    5611         final StringBuilder buf = new StringBuilder(text.length() + increase);
    5612         while (end != INDEX_NOT_FOUND) {
    5613             buf.append(text, start, end).append(replacement);
    5614             start = end + replLength;
    5615             if (--max == 0) {
    5616                 break;
    5617             }
    5618             end = searchText.indexOf(searchString, start);
    5619         }
    5620         buf.append(text, start, text.length());
    5621         return buf.toString();
    5622     }
    5623
    5624    /**
    5625     * <p>Case insensitively replaces a String with another String inside a larger String,
    5626     * for the first {@code max} values of the search String.</p>
    5627     *
    5628     * <p>A {@code null} reference passed to this method is a no-op.</p>
    5629     *
    5630     * <pre>
    5631     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
    5632     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
    5633     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
    5634     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
    5635     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
    5636     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
    5637     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
    5638     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
    5639     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
    5640     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
    5641     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
    5642     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
    5643     * </pre>
    5644     *
    5645     * @param text  text to search and replace in, may be null
    5646     * @param searchString  the String to search for (case insensitive), may be null
    5647     * @param replacement  the String to replace it with, may be null
    5648     * @param max  maximum number of values to replace, or {@code -1} if no maximum
    5649     * @return the text with any replacements processed,
    5650     *  {@code null} if null String input
    5651     * @since 3.5
    5652     */
    5653    public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
    5654        return replace(text, searchString, replacement, max, true);
    5655    }
    5656
    5657    /**
    5658     * <p>
    5659     * Replaces all occurrences of Strings within another String.
    5660     * </p>
    5661     *
    5662     * <p>
    5663     * A {@code null} reference passed to this method is a no-op, or if
    5664     * any "search string" or "string to replace" is null, that replace will be
    5665     * ignored. This will not repeat. For repeating replaces, call the
    5666     * overloaded method.
    5667     * </p>
    5668     *
    5669     * <pre>
    5670     *  StringUtils.replaceEach(null, *, *)        = null
    5671     *  StringUtils.replaceEach("", *, *)          = ""
    5672     *  StringUtils.replaceEach("aba", null, null) = "aba"
    5673     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
    5674     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
    5675     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
    5676     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
    5677     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
    5678     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    5679     *  (example of how it does not repeat)
    5680     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    5681     * </pre>
    5682     *
    5683     * @param text
    5684     *            text to search and replace in, no-op if null
    5685     * @param searchList
    5686     *            the Strings to search for, no-op if null
    5687     * @param replacementList
    5688     *            the Strings to replace them with, no-op if null
    5689     * @return the text with any replacements processed, {@code null} if
    5690     *         null String input
    5691     * @throws IllegalArgumentException
    5692     *             if the lengths of the arrays are not the same (null is ok,
    5693     *             and/or size 0)
    5694     * @since 2.4
    5695     */
    5696    public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
    5697        return replaceEach(text, searchList, replacementList, false, 0);
    5698    }
    5699
    5700    /**
    5701     * <p>
    5702     * Replaces all occurrences of Strings within another String.
    5703     * </p>
    5704     *
    5705     * <p>
    5706     * A {@code null} reference passed to this method is a no-op, or if
    5707     * any "search string" or "string to replace" is null, that replace will be
    5708     * ignored.
    5709     * </p>
    5710     *
    5711     * <pre>
    5712     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
    5713     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
    5714     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
    5715     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
    5716     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
    5717     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
    5718     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
    5719     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
    5720     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
    5721     *  (example of how it repeats)
    5722     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
    5723     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
    5724     * </pre>
    5725     *
    5726     * @param text
    5727     *            text to search and replace in, no-op if null
    5728     * @param searchList
    5729     *            the Strings to search for, no-op if null
    5730     * @param replacementList
    5731     *            the Strings to replace them with, no-op if null
    5732     * @return the text with any replacements processed, {@code null} if
    5733     *         null String input
    5734     * @throws IllegalStateException
    5735     *             if the search is repeating and there is an endless loop due
    5736     *             to outputs of one being inputs to another
    5737     * @throws IllegalArgumentException
    5738     *             if the lengths of the arrays are not the same (null is ok,
    5739     *             and/or size 0)
    5740     * @since 2.4
    5741     */
    5742    public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
    5743        // timeToLive should be 0 if not used or nothing to replace, else it's
    5744        // the length of the replace array
    5745        final int timeToLive = searchList == null ? 0 : searchList.length;
    5746        return replaceEach(text, searchList, replacementList, true, timeToLive);
    5747    }
    5748
    5749    /**
    5750     * <p>
    5751     * Replace all occurrences of Strings within another String.
    5752     * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
    5753     * {@link #replaceEach(String, String[], String[])}
    5754     * </p>
    5755     *
    5756     * <p>
    5757     * A {@code null} reference passed to this method is a no-op, or if
    5758     * any "search string" or "string to replace" is null, that replace will be
    5759     * ignored.
    5760     * </p>
    5761     *
    5762     * <pre>
    5763     *  StringUtils.replaceEach(null, *, *, *, *) = null
    5764     *  StringUtils.replaceEach("", *, *, *, *) = ""
    5765     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
    5766     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
    5767     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
    5768     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
    5769     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
    5770     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
    5771     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
    5772     *  (example of how it repeats)
    5773     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
    5774     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
    5775     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
    5776     * </pre>
    5777     *
    5778     * @param text
    5779     *            text to search and replace in, no-op if null
    5780     * @param searchList
    5781     *            the Strings to search for, no-op if null
    5782     * @param replacementList
    5783     *            the Strings to replace them with, no-op if null
    5784     * @param repeat if true, then replace repeatedly
    5785     *       until there are no more possible replacements or timeToLive < 0
    5786     * @param timeToLive
    5787     *            if less than 0 then there is a circular reference and endless
    5788     *            loop
    5789     * @return the text with any replacements processed, {@code null} if
    5790     *         null String input
    5791     * @throws IllegalStateException
    5792     *             if the search is repeating and there is an endless loop due
    5793     *             to outputs of one being inputs to another
    5794     * @throws IllegalArgumentException
    5795     *             if the lengths of the arrays are not the same (null is ok,
    5796     *             and/or size 0)
    5797     * @since 2.4
    5798     */
    5799    private static String replaceEach(
    5800            final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
    5801
    5802        // mchyzer Performance note: This creates very few new objects (one major goal)
    5803        // let me know if there are performance requests, we can create a harness to measure
    5804
    5805        if (text == null || text.isEmpty() || searchList == null ||
    5806                searchList.length == 0 || replacementList == null || replacementList.length == 0) {
    5807            return text;
    5808        }
    5809
    5810        // if recursing, this shouldn't be less than 0
    5811        if (timeToLive < 0) {
    5812            throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
    5813                                            "output of one loop is the input of another");
    5814        }
    5815
    5816        final int searchLength = searchList.length;
    5817        final int replacementLength = replacementList.length;
    5818
    5819        // make sure lengths are ok, these need to be equal
    5820        if (searchLength != replacementLength) {
    5821            throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    5822                + searchLength
    5823                + " vs "
    5824                + replacementLength);
    5825        }
    5826
    5827        // keep track of which still have matches
    5828        final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    5829
    5830        // index on index that the match was found
    5831        int textIndex = -1;
    5832        int replaceIndex = -1;
    5833        int tempIndex = -1;
    5834
    5835        // index of replace array that will replace the search string found
    5836        // NOTE: logic duplicated below START
    5837        for (int i = 0; i < searchLength; i++) {
    5838            if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
    5839                    searchList[i].isEmpty() || replacementList[i] == null) {
    5840                continue;
    5841            }
    5842            tempIndex = text.indexOf(searchList[i]);
    5843
    5844            // see if we need to keep searching for this
    5845            if (tempIndex == -1) {
    5846                noMoreMatchesForReplIndex[i] = true;
    5847            } else {
    5848                if (textIndex == -1 || tempIndex < textIndex) {
    5849                    textIndex = tempIndex;
    5850                    replaceIndex = i;
    5851                }
    5852            }
    5853        }
    5854        // NOTE: logic mostly below END
    5855
    5856        // no search strings found, we are done
    5857        if (textIndex == -1) {
    5858            return text;
    5859        }
    5860
    5861        int start = 0;
    5862
    5863        // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
    5864        int increase = 0;
    5865
    5866        // count the replacement text elements that are larger than their corresponding text being replaced
    5867        for (int i = 0; i < searchList.length; i++) {
    5868            if (searchList[i] == null || replacementList[i] == null) {
    5869                continue;
    5870            }
    5871            final int greater = replacementList[i].length() - searchList[i].length();
    5872            if (greater > 0) {
    5873                increase += 3 * greater; // assume 3 matches
    5874            }
    5875        }
    5876        // have upper-bound at 20% increase, then let Java take over
    5877        increase = Math.min(increase, text.length() / 5);
    5878
    5879        final StringBuilder buf = new StringBuilder(text.length() + increase);
    5880
    5881        while (textIndex != -1) {
    5882
    5883            for (int i = start; i < textIndex; i++) {
    5884                buf.append(text.charAt(i));
    5885            }
    5886            buf.append(replacementList[replaceIndex]);
    5887
    5888            start = textIndex + searchList[replaceIndex].length();
    5889
    5890            textIndex = -1;
    5891            replaceIndex = -1;
    5892            tempIndex = -1;
    5893            // find the next earliest match
    5894            // NOTE: logic mostly duplicated above START
    5895            for (int i = 0; i < searchLength; i++) {
    5896                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
    5897                        searchList[i].isEmpty() || replacementList[i] == null) {
    5898                    continue;
    5899                }
    5900                tempIndex = text.indexOf(searchList[i], start);
    5901
    5902                // see if we need to keep searching for this
    5903                if (tempIndex == -1) {
    5904                    noMoreMatchesForReplIndex[i] = true;
    5905                } else {
    5906                    if (textIndex == -1 || tempIndex < textIndex) {
    5907                        textIndex = tempIndex;
    5908                        replaceIndex = i;
    5909                    }
    5910                }
    5911            }
    5912            // NOTE: logic duplicated above END
    5913
    5914        }
    5915        final int textLength = text.length();
    5916        for (int i = start; i < textLength; i++) {
    5917            buf.append(text.charAt(i));
    5918        }
    5919        final String result = buf.toString();
    5920        if (!repeat) {
    5921            return result;
    5922        }
    5923
    5924        return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    5925    }
    5926
    5927    // Replace, character based
    5928    //-----------------------------------------------------------------------
    5929    /**
    5930     * <p>Replaces all occurrences of a character in a String with another.
    5931     * This is a null-safe version of {@link String#replace(char, char)}.</p>
    5932     *
    5933     * <p>A {@code null} string input returns {@code null}.
    5934     * An empty ("") string input returns an empty string.</p>
    5935     *
    5936     * <pre>
    5937     * StringUtils.replaceChars(null, *, *)        = null
    5938     * StringUtils.replaceChars("", *, *)          = ""
    5939     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    5940     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    5941     * </pre>
    5942     *
    5943     * @param str  String to replace characters in, may be null
    5944     * @param searchChar  the character to search for, may be null
    5945     * @param replaceChar  the character to replace, may be null
    5946     * @return modified String, {@code null} if null string input
    5947     * @since 2.0
    5948     */
    5949    public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
    5950        if (str == null) {
    5951            return null;
    5952        }
    5953        return str.replace(searchChar, replaceChar);
    5954    }
    5955
    5956    /**
    5957     * <p>Replaces multiple characters in a String in one go.
    5958     * This method can also be used to delete characters.</p>
    5959     *
    5960     * <p>For example:<br>
    5961     * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
    5962     *
    5963     * <p>A {@code null} string input returns {@code null}.
    5964     * An empty ("") string input returns an empty string.
    5965     * A null or empty set of search characters returns the input string.</p>
    5966     *
    5967     * <p>The length of the search characters should normally equal the length
    5968     * of the replace characters.
    5969     * If the search characters is longer, then the extra search characters
    5970     * are deleted.
    5971     * If the search characters is shorter, then the extra replace characters
    5972     * are ignored.</p>
    5973     *
    5974     * <pre>
    5975     * StringUtils.replaceChars(null, *, *)           = null
    5976     * StringUtils.replaceChars("", *, *)             = ""
    5977     * StringUtils.replaceChars("abc", null, *)       = "abc"
    5978     * StringUtils.replaceChars("abc", "", *)         = "abc"
    5979     * StringUtils.replaceChars("abc", "b", null)     = "ac"
    5980     * StringUtils.replaceChars("abc", "b", "")       = "ac"
    5981     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    5982     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    5983     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    5984     * </pre>
    5985     *
    5986     * @param str  String to replace characters in, may be null
    5987     * @param searchChars  a set of characters to search for, may be null
    5988     * @param replaceChars  a set of characters to replace, may be null
    5989     * @return modified String, {@code null} if null string input
    5990     * @since 2.0
    5991     */
    5992    public static String replaceChars(final String str, final String searchChars, String replaceChars) {
    5993        if (isEmpty(str) || isEmpty(searchChars)) {
    5994            return str;
    5995        }
    5996        if (replaceChars == null) {
    5997            replaceChars = EMPTY;
    5998        }
    5999        boolean modified = false;
    6000        final int replaceCharsLength = replaceChars.length();
    6001        final int strLength = str.length();
    6002        final StringBuilder buf = new StringBuilder(strLength);
    6003        for (int i = 0; i < strLength; i++) {
    6004            final char ch = str.charAt(i);
    6005            final int index = searchChars.indexOf(ch);
    6006            if (index >= 0) {
    6007                modified = true;
    6008                if (index < replaceCharsLength) {
    6009                    buf.append(replaceChars.charAt(index));
    6010                }
    6011            } else {
    6012                buf.append(ch);
    6013            }
    6014        }
    6015        if (modified) {
    6016            return buf.toString();
    6017        }
    6018        return str;
    6019    }
    6020
    6021    // Overlay
    6022    //-----------------------------------------------------------------------
    6023    /**
    6024     * <p>Overlays part of a String with another String.</p>
    6025     *
    6026     * <p>A {@code null} string input returns {@code null}.
    6027     * A negative index is treated as zero.
    6028     * An index greater than the string length is treated as the string length.
    6029     * The start index is always the smaller of the two indices.</p>
    6030     *
    6031     * <pre>
    6032     * StringUtils.overlay(null, *, *, *)            = null
    6033     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    6034     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    6035     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    6036     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    6037     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    6038     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    6039     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    6040     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    6041     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    6042     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    6043     * </pre>
    6044     *
    6045     * @param str  the String to do overlaying in, may be null
    6046     * @param overlay  the String to overlay, may be null
    6047     * @param start  the position to start overlaying at
    6048     * @param end  the position to stop overlaying before
    6049     * @return overlayed String, {@code null} if null String input
    6050     * @since 2.0
    6051     */
    6052    public static String overlay(final String str, String overlay, int start, int end) {
    6053        if (str == null) {
    6054            return null;
    6055        }
    6056        if (overlay == null) {
    6057            overlay = EMPTY;
    6058        }
    6059        final int len = str.length();
    6060        if (start < 0) {
    6061            start = 0;
    6062        }
    6063        if (start > len) {
    6064            start = len;
    6065        }
    6066        if (end < 0) {
    6067            end = 0;
    6068        }
    6069        if (end > len) {
    6070            end = len;
    6071        }
    6072        if (start > end) {
    6073            final int temp = start;
    6074            start = end;
    6075            end = temp;
    6076        }
    6077        return str.substring(0, start) +
    6078            overlay +
    6079            str.substring(end);
    6080    }
    6081
    6082    // Chomping
    6083    //-----------------------------------------------------------------------
    6084    /**
    6085     * <p>Removes one newline from end of a String if it's there,
    6086     * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
    6087     * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
    6088     *
    6089     * <p>NOTE: This method changed in 2.0.
    6090     * It now more closely matches Perl chomp.</p>
    6091     *
    6092     * <pre>
    6093     * StringUtils.chomp(null)          = null
    6094     * StringUtils.chomp("")            = ""
    6095     * StringUtils.chomp("abc \r")      = "abc "
    6096     * StringUtils.chomp("abc\n")       = "abc"
    6097     * StringUtils.chomp("abc\r\n")     = "abc"
    6098     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
    6099     * StringUtils.chomp("abc\n\r")     = "abc\n"
    6100     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
    6101     * StringUtils.chomp("\r")          = ""
    6102     * StringUtils.chomp("\n")          = ""
    6103     * StringUtils.chomp("\r\n")        = ""
    6104     * </pre>
    6105     *
    6106     * @param str  the String to chomp a newline from, may be null
    6107     * @return String without newline, {@code null} if null String input
    6108     */
    6109    public static String chomp(final String str) {
    6110        if (isEmpty(str)) {
    6111            return str;
    6112        }
    6113
    6114        if (str.length() == 1) {
    6115            final char ch = str.charAt(0);
    6116            if (ch == CharUtils.CR || ch == CharUtils.LF) {
    6117                return EMPTY;
    6118            }
    6119            return str;
    6120        }
    6121
    6122        int lastIdx = str.length() - 1;
    6123        final char last = str.charAt(lastIdx);
    6124
    6125        if (last == CharUtils.LF) {
    6126            if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    6127                lastIdx--;
    6128            }
    6129        } else if (last != CharUtils.CR) {
    6130            lastIdx++;
    6131        }
    6132        return str.substring(0, lastIdx);
    6133    }
    6134
    6135    /**
    6136     * <p>Removes {@code separator} from the end of
    6137     * {@code str} if it's there, otherwise leave it alone.</p>
    6138     *
    6139     * <p>NOTE: This method changed in version 2.0.
    6140     * It now more closely matches Perl chomp.
    6141     * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
    6142     * This method uses {@link String#endsWith(String)}.</p>
    6143     *
    6144     * <pre>
    6145     * StringUtils.chomp(null, *)         = null
    6146     * StringUtils.chomp("", *)           = ""
    6147     * StringUtils.chomp("foobar", "bar") = "foo"
    6148     * StringUtils.chomp("foobar", "baz") = "foobar"
    6149     * StringUtils.chomp("foo", "foo")    = ""
    6150     * StringUtils.chomp("foo ", "foo")   = "foo "
    6151     * StringUtils.chomp(" foo", "foo")   = " "
    6152     * StringUtils.chomp("foo", "foooo")  = "foo"
    6153     * StringUtils.chomp("foo", "")       = "foo"
    6154     * StringUtils.chomp("foo", null)     = "foo"
    6155     * </pre>
    6156     *
    6157     * @param str  the String to chomp from, may be null
    6158     * @param separator  separator String, may be null
    6159     * @return String without trailing separator, {@code null} if null String input
    6160     * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
    6161     */
    6162    @Deprecated
    6163    public static String chomp(final String str, final String separator) {
    6164        return removeEnd(str,separator);
    6165    }
    6166
    6167    // Chopping
    6168    //-----------------------------------------------------------------------
    6169    /**
    6170     * <p>Remove the last character from a String.</p>
    6171     *
    6172     * <p>If the String ends in {@code \r\n}, then remove both
    6173     * of them.</p>
    6174     *
    6175     * <pre>
    6176     * StringUtils.chop(null)          = null
    6177     * StringUtils.chop("")            = ""
    6178     * StringUtils.chop("abc \r")      = "abc "
    6179     * StringUtils.chop("abc\n")       = "abc"
    6180     * StringUtils.chop("abc\r\n")     = "abc"
    6181     * StringUtils.chop("abc")         = "ab"
    6182     * StringUtils.chop("abc\nabc")    = "abc\nab"
    6183     * StringUtils.chop("a")           = ""
    6184     * StringUtils.chop("\r")          = ""
    6185     * StringUtils.chop("\n")          = ""
    6186     * StringUtils.chop("\r\n")        = ""
    6187     * </pre>
    6188     *
    6189     * @param str  the String to chop last character from, may be null
    6190     * @return String without last character, {@code null} if null String input
    6191     */
    6192    public static String chop(final String str) {
    6193        if (str == null) {
    6194            return null;
    6195        }
    6196        final int strLen = str.length();
    6197        if (strLen < 2) {
    6198            return EMPTY;
    6199        }
    6200        final int lastIdx = strLen - 1;
    6201        final String ret = str.substring(0, lastIdx);
    6202        final char last = str.charAt(lastIdx);
    6203        if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
    6204            return ret.substring(0, lastIdx - 1);
    6205        }
    6206        return ret;
    6207    }
    6208
    6209    // Conversion
    6210    //-----------------------------------------------------------------------
    6211
    6212    // Padding
    6213    //-----------------------------------------------------------------------
    6214    /**
    6215     * <p>Repeat a String {@code repeat} times to form a
    6216     * new String.</p>
    6217     *
    6218     * <pre>
    6219     * StringUtils.repeat(null, 2) = null
    6220     * StringUtils.repeat("", 0)   = ""
    6221     * StringUtils.repeat("", 2)   = ""
    6222     * StringUtils.repeat("a", 3)  = "aaa"
    6223     * StringUtils.repeat("ab", 2) = "abab"
    6224     * StringUtils.repeat("a", -2) = ""
    6225     * </pre>
    6226     *
    6227     * @param str  the String to repeat, may be null
    6228     * @param repeat  number of times to repeat str, negative treated as zero
    6229     * @return a new String consisting of the original String repeated,
    6230     *  {@code null} if null String input
    6231     */
    6232    public static String repeat(final String str, final int repeat) {
    6233        // Performance tuned for 2.0 (JDK1.4)
    6234
    6235        if (str == null) {
    6236            return null;
    6237        }
    6238        if (repeat <= 0) {
    6239            return EMPTY;
    6240        }
    6241        final int inputLength = str.length();
    6242        if (repeat == 1 || inputLength == 0) {
    6243            return str;
    6244        }
    6245        if (inputLength == 1 && repeat <= PAD_LIMIT) {
    6246            return repeat(str.charAt(0), repeat);
    6247        }
    6248
    6249        final int outputLength = inputLength * repeat;
    6250        switch (inputLength) {
    6251            case 1 :
    6252                return repeat(str.charAt(0), repeat);
    6253            case 2 :
    6254                final char ch0 = str.charAt(0);
    6255                final char ch1 = str.charAt(1);
    6256                final char[] output2 = new char[outputLength];
    6257                for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
    6258                    output2[i] = ch0;
    6259                    output2[i + 1] = ch1;
    6260                }
    6261                return new String(output2);
    6262            default :
    6263                final StringBuilder buf = new StringBuilder(outputLength);
    6264                for (int i = 0; i < repeat; i++) {
    6265                    buf.append(str);
    6266                }
    6267                return buf.toString();
    6268        }
    6269    }
    6270
    6271    /**
    6272     * <p>Repeat a String {@code repeat} times to form a
    6273     * new String, with a String separator injected each time. </p>
    6274     *
    6275     * <pre>
    6276     * StringUtils.repeat(null, null, 2) = null
    6277     * StringUtils.repeat(null, "x", 2)  = null
    6278     * StringUtils.repeat("", null, 0)   = ""
    6279     * StringUtils.repeat("", "", 2)     = ""
    6280     * StringUtils.repeat("", "x", 3)    = "xxx"
    6281     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    6282     * </pre>
    6283     *
    6284     * @param str        the String to repeat, may be null
    6285     * @param separator  the String to inject, may be null
    6286     * @param repeat     number of times to repeat str, negative treated as zero
    6287     * @return a new String consisting of the original String repeated,
    6288     *  {@code null} if null String input
    6289     * @since 2.5
    6290     */
    6291    public static String repeat(final String str, final String separator, final int repeat) {
    6292        if(str == null || separator == null) {
    6293            return repeat(str, repeat);
    6294        }
    6295        // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    6296        final String result = repeat(str + separator, repeat);
    6297        return removeEnd(result, separator);
    6298    }
    6299
    6300    /**
    6301     * <p>Returns padding using the specified delimiter repeated
    6302     * to a given length.</p>
    6303     *
    6304     * <pre>
    6305     * StringUtils.repeat('e', 0)  = ""
    6306     * StringUtils.repeat('e', 3)  = "eee"
    6307     * StringUtils.repeat('e', -2) = ""
    6308     * </pre>
    6309     *
    6310     * <p>Note: this method does not support padding with
    6311     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    6312     * as they require a pair of {@code char}s to be represented.
    6313     * If you are needing to support full I18N of your applications
    6314     * consider using {@link #repeat(String, int)} instead.
    6315     * </p>
    6316     *
    6317     * @param ch  character to repeat
    6318     * @param repeat  number of times to repeat char, negative treated as zero
    6319     * @return String with repeated character
    6320     * @see #repeat(String, int)
    6321     */
    6322    public static String repeat(final char ch, final int repeat) {
    6323        if (repeat <= 0) {
    6324            return EMPTY;
    6325        }
    6326        final char[] buf = new char[repeat];
    6327        for (int i = repeat - 1; i >= 0; i--) {
    6328            buf[i] = ch;
    6329        }
    6330        return new String(buf);
    6331    }
    6332
    6333    /**
    6334     * <p>Right pad a String with spaces (' ').</p>
    6335     *
    6336     * <p>The String is padded to the size of {@code size}.</p>
    6337     *
    6338     * <pre>
    6339     * StringUtils.rightPad(null, *)   = null
    6340     * StringUtils.rightPad("", 3)     = "   "
    6341     * StringUtils.rightPad("bat", 3)  = "bat"
    6342     * StringUtils.rightPad("bat", 5)  = "bat  "
    6343     * StringUtils.rightPad("bat", 1)  = "bat"
    6344     * StringUtils.rightPad("bat", -1) = "bat"
    6345     * </pre>
    6346     *
    6347     * @param str  the String to pad out, may be null
    6348     * @param size  the size to pad to
    6349     * @return right padded String or original String if no padding is necessary,
    6350     *  {@code null} if null String input
    6351     */
    6352    public static String rightPad(final String str, final int size) {
    6353        return rightPad(str, size, ' ');
    6354    }
    6355
    6356    /**
    6357     * <p>Right pad a String with a specified character.</p>
    6358     *
    6359     * <p>The String is padded to the size of {@code size}.</p>
    6360     *
    6361     * <pre>
    6362     * StringUtils.rightPad(null, *, *)     = null
    6363     * StringUtils.rightPad("", 3, 'z')     = "zzz"
    6364     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    6365     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    6366     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    6367     * StringUtils.rightPad("bat", -1, 'z') = "bat"
    6368     * </pre>
    6369     *
    6370     * @param str  the String to pad out, may be null
    6371     * @param size  the size to pad to
    6372     * @param padChar  the character to pad with
    6373     * @return right padded String or original String if no padding is necessary,
    6374     *  {@code null} if null String input
    6375     * @since 2.0
    6376     */
    6377    public static String rightPad(final String str, final int size, final char padChar) {
    6378        if (str == null) {
    6379            return null;
    6380        }
    6381        final int pads = size - str.length();
    6382        if (pads <= 0) {
    6383            return str; // returns original String when possible
    6384        }
    6385        if (pads > PAD_LIMIT) {
    6386            return rightPad(str, size, String.valueOf(padChar));
    6387        }
    6388        return str.concat(repeat(padChar, pads));
    6389    }
    6390
    6391    /**
    6392     * <p>Right pad a String with a specified String.</p>
    6393     *
    6394     * <p>The String is padded to the size of {@code size}.</p>
    6395     *
    6396     * <pre>
    6397     * StringUtils.rightPad(null, *, *)      = null
    6398     * StringUtils.rightPad("", 3, "z")      = "zzz"
    6399     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    6400     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    6401     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    6402     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    6403     * StringUtils.rightPad("bat", -1, "yz") = "bat"
    6404     * StringUtils.rightPad("bat", 5, null)  = "bat  "
    6405     * StringUtils.rightPad("bat", 5, "")    = "bat  "
    6406     * </pre>
    6407     *
    6408     * @param str  the String to pad out, may be null
    6409     * @param size  the size to pad to
    6410     * @param padStr  the String to pad with, null or empty treated as single space
    6411     * @return right padded String or original String if no padding is necessary,
    6412     *  {@code null} if null String input
    6413     */
    6414    public static String rightPad(final String str, final int size, String padStr) {
    6415        if (str == null) {
    6416            return null;
    6417        }
    6418        if (isEmpty(padStr)) {
    6419            padStr = SPACE;
    6420        }
    6421        final int padLen = padStr.length();
    6422        final int strLen = str.length();
    6423        final int pads = size - strLen;
    6424        if (pads <= 0) {
    6425            return str; // returns original String when possible
    6426        }
    6427        if (padLen == 1 && pads <= PAD_LIMIT) {
    6428            return rightPad(str, size, padStr.charAt(0));
    6429        }
    6430
    6431        if (pads == padLen) {
    6432            return str.concat(padStr);
    6433        } else if (pads < padLen) {
    6434            return str.concat(padStr.substring(0, pads));
    6435        } else {
    6436            final char[] padding = new char[pads];
    6437            final char[] padChars = padStr.toCharArray();
    6438            for (int i = 0; i < pads; i++) {
    6439                padding[i] = padChars[i % padLen];
    6440            }
    6441            return str.concat(new String(padding));
    6442        }
    6443    }
    6444
    6445    /**
    6446     * <p>Left pad a String with spaces (' ').</p>
    6447     *
    6448     * <p>The String is padded to the size of {@code size}.</p>
    6449     *
    6450     * <pre>
    6451     * StringUtils.leftPad(null, *)   = null
    6452     * StringUtils.leftPad("", 3)     = "   "
    6453     * StringUtils.leftPad("bat", 3)  = "bat"
    6454     * StringUtils.leftPad("bat", 5)  = "  bat"
    6455     * StringUtils.leftPad("bat", 1)  = "bat"
    6456     * StringUtils.leftPad("bat", -1) = "bat"
    6457     * </pre>
    6458     *
    6459     * @param str  the String to pad out, may be null
    6460     * @param size  the size to pad to
    6461     * @return left padded String or original String if no padding is necessary,
    6462     *  {@code null} if null String input
    6463     */
    6464    public static String leftPad(final String str, final int size) {
    6465        return leftPad(str, size, ' ');
    6466    }
    6467
    6468    /**
    6469     * <p>Left pad a String with a specified character.</p>
    6470     *
    6471     * <p>Pad to a size of {@code size}.</p>
    6472     *
    6473     * <pre>
    6474     * StringUtils.leftPad(null, *, *)     = null
    6475     * StringUtils.leftPad("", 3, 'z')     = "zzz"
    6476     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    6477     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    6478     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    6479     * StringUtils.leftPad("bat", -1, 'z') = "bat"
    6480     * </pre>
    6481     *
    6482     * @param str  the String to pad out, may be null
    6483     * @param size  the size to pad to
    6484     * @param padChar  the character to pad with
    6485     * @return left padded String or original String if no padding is necessary,
    6486     *  {@code null} if null String input
    6487     * @since 2.0
    6488     */
    6489    public static String leftPad(final String str, final int size, final char padChar) {
    6490        if (str == null) {
    6491            return null;
    6492        }
    6493        final int pads = size - str.length();
    6494        if (pads <= 0) {
    6495            return str; // returns original String when possible
    6496        }
    6497        if (pads > PAD_LIMIT) {
    6498            return leftPad(str, size, String.valueOf(padChar));
    6499        }
    6500        return repeat(padChar, pads).concat(str);
    6501    }
    6502
    6503    /**
    6504     * <p>Left pad a String with a specified String.</p>
    6505     *
    6506     * <p>Pad to a size of {@code size}.</p>
    6507     *
    6508     * <pre>
    6509     * StringUtils.leftPad(null, *, *)      = null
    6510     * StringUtils.leftPad("", 3, "z")      = "zzz"
    6511     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    6512     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    6513     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    6514     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    6515     * StringUtils.leftPad("bat", -1, "yz") = "bat"
    6516     * StringUtils.leftPad("bat", 5, null)  = "  bat"
    6517     * StringUtils.leftPad("bat", 5, "")    = "  bat"
    6518     * </pre>
    6519     *
    6520     * @param str  the String to pad out, may be null
    6521     * @param size  the size to pad to
    6522     * @param padStr  the String to pad with, null or empty treated as single space
    6523     * @return left padded String or original String if no padding is necessary,
    6524     *  {@code null} if null String input
    6525     */
    6526    public static String leftPad(final String str, final int size, String padStr) {
    6527        if (str == null) {
    6528            return null;
    6529        }
    6530        if (isEmpty(padStr)) {
    6531            padStr = SPACE;
    6532        }
    6533        final int padLen = padStr.length();
    6534        final int strLen = str.length();
    6535        final int pads = size - strLen;
    6536        if (pads <= 0) {
    6537            return str; // returns original String when possible
    6538        }
    6539        if (padLen == 1 && pads <= PAD_LIMIT) {
    6540            return leftPad(str, size, padStr.charAt(0));
    6541        }
    6542
    6543        if (pads == padLen) {
    6544            return padStr.concat(str);
    6545        } else if (pads < padLen) {
    6546            return padStr.substring(0, pads).concat(str);
    6547        } else {
    6548            final char[] padding = new char[pads];
    6549            final char[] padChars = padStr.toCharArray();
    6550            for (int i = 0; i < pads; i++) {
    6551                padding[i] = padChars[i % padLen];
    6552            }
    6553            return new String(padding).concat(str);
    6554        }
    6555    }
    6556
    6557    /**
    6558     * Gets a CharSequence length or {@code 0} if the CharSequence is
    6559     * {@code null}.
    6560     *
    6561     * @param cs
    6562     *            a CharSequence or {@code null}
    6563     * @return CharSequence length or {@code 0} if the CharSequence is
    6564     *         {@code null}.
    6565     * @since 2.4
    6566     * @since 3.0 Changed signature from length(String) to length(CharSequence)
    6567     */
    6568    public static int length(final CharSequence cs) {
    6569        return cs == null ? 0 : cs.length();
    6570    }
    6571
    6572    // Centering
    6573    //-----------------------------------------------------------------------
    6574    /**
    6575     * <p>Centers a String in a larger String of size {@code size}
    6576     * using the space character (' ').</p>
    6577     *
    6578     * <p>If the size is less than the String length, the String is returned.
    6579     * A {@code null} String returns {@code null}.
    6580     * A negative size is treated as zero.</p>
    6581     *
    6582     * <p>Equivalent to {@code center(str, size, " ")}.</p>
    6583     *
    6584     * <pre>
    6585     * StringUtils.center(null, *)   = null
    6586     * StringUtils.center("", 4)     = "    "
    6587     * StringUtils.center("ab", -1)  = "ab"
    6588     * StringUtils.center("ab", 4)   = " ab "
    6589     * StringUtils.center("abcd", 2) = "abcd"
    6590     * StringUtils.center("a", 4)    = " a  "
    6591     * </pre>
    6592     *
    6593     * @param str  the String to center, may be null
    6594     * @param size  the int size of new String, negative treated as zero
    6595     * @return centered String, {@code null} if null String input
    6596     */
    6597    public static String center(final String str, final int size) {
    6598        return center(str, size, ' ');
    6599    }
    6600
    6601    /**
    6602     * <p>Centers a String in a larger String of size {@code size}.
    6603     * Uses a supplied character as the value to pad the String with.</p>
    6604     *
    6605     * <p>If the size is less than the String length, the String is returned.
    6606     * A {@code null} String returns {@code null}.
    6607     * A negative size is treated as zero.</p>
    6608     *
    6609     * <pre>
    6610     * StringUtils.center(null, *, *)     = null
    6611     * StringUtils.center("", 4, ' ')     = "    "
    6612     * StringUtils.center("ab", -1, ' ')  = "ab"
    6613     * StringUtils.center("ab", 4, ' ')   = " ab "
    6614     * StringUtils.center("abcd", 2, ' ') = "abcd"
    6615     * StringUtils.center("a", 4, ' ')    = " a  "
    6616     * StringUtils.center("a", 4, 'y')    = "yayy"
    6617     * </pre>
    6618     *
    6619     * @param str  the String to center, may be null
    6620     * @param size  the int size of new String, negative treated as zero
    6621     * @param padChar  the character to pad the new String with
    6622     * @return centered String, {@code null} if null String input
    6623     * @since 2.0
    6624     */
    6625    public static String center(String str, final int size, final char padChar) {
    6626        if (str == null || size <= 0) {
    6627            return str;
    6628        }
    6629        final int strLen = str.length();
    6630        final int pads = size - strLen;
    6631        if (pads <= 0) {
    6632            return str;
    6633        }
    6634        str = leftPad(str, strLen + pads / 2, padChar);
    6635        str = rightPad(str, size, padChar);
    6636        return str;
    6637    }
    6638
    6639    /**
    6640     * <p>Centers a String in a larger String of size {@code size}.
    6641     * Uses a supplied String as the value to pad the String with.</p>
    6642     *
    6643     * <p>If the size is less than the String length, the String is returned.
    6644     * A {@code null} String returns {@code null}.
    6645     * A negative size is treated as zero.</p>
    6646     *
    6647     * <pre>
    6648     * StringUtils.center(null, *, *)     = null
    6649     * StringUtils.center("", 4, " ")     = "    "
    6650     * StringUtils.center("ab", -1, " ")  = "ab"
    6651     * StringUtils.center("ab", 4, " ")   = " ab "
    6652     * StringUtils.center("abcd", 2, " ") = "abcd"
    6653     * StringUtils.center("a", 4, " ")    = " a  "
    6654     * StringUtils.center("a", 4, "yz")   = "yayz"
    6655     * StringUtils.center("abc", 7, null) = "  abc  "
    6656     * StringUtils.center("abc", 7, "")   = "  abc  "
    6657     * </pre>
    6658     *
    6659     * @param str  the String to center, may be null
    6660     * @param size  the int size of new String, negative treated as zero
    6661     * @param padStr  the String to pad the new String with, must not be null or empty
    6662     * @return centered String, {@code null} if null String input
    6663     * @throws IllegalArgumentException if padStr is {@code null} or empty
    6664     */
    6665    public static String center(String str, final int size, String padStr) {
    6666        if (str == null || size <= 0) {
    6667            return str;
    6668        }
    6669        if (isEmpty(padStr)) {
    6670            padStr = SPACE;
    6671        }
    6672        final int strLen = str.length();
    6673        final int pads = size - strLen;
    6674        if (pads <= 0) {
    6675            return str;
    6676        }
    6677        str = leftPad(str, strLen + pads / 2, padStr);
    6678        str = rightPad(str, size, padStr);
    6679        return str;
    6680    }
    6681
    6682    // Case conversion
    6683    //-----------------------------------------------------------------------
    6684    /**
    6685     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
    6686     *
    6687     * <p>A {@code null} input String returns {@code null}.</p>
    6688     *
    6689     * <pre>
    6690     * StringUtils.upperCase(null)  = null
    6691     * StringUtils.upperCase("")    = ""
    6692     * StringUtils.upperCase("aBc") = "ABC"
    6693     * </pre>
    6694     *
    6695     * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
    6696     * the result of this method is affected by the current locale.
    6697     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    6698     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    6699     *
    6700     * @param str  the String to upper case, may be null
    6701     * @return the upper cased String, {@code null} if null String input
    6702     */
    6703    public static String upperCase(final String str) {
    6704        if (str == null) {
    6705            return null;
    6706        }
    6707        return str.toUpperCase();
    6708    }
    6709
    6710    /**
    6711     * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
    6712     *
    6713     * <p>A {@code null} input String returns {@code null}.</p>
    6714     *
    6715     * <pre>
    6716     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    6717     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    6718     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    6719     * </pre>
    6720     *
    6721     * @param str  the String to upper case, may be null
    6722     * @param locale  the locale that defines the case transformation rules, must not be null
    6723     * @return the upper cased String, {@code null} if null String input
    6724     * @since 2.5
    6725     */
    6726    public static String upperCase(final String str, final Locale locale) {
    6727        if (str == null) {
    6728            return null;
    6729        }
    6730        return str.toUpperCase(locale);
    6731    }
    6732
    6733    /**
    6734     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
    6735     *
    6736     * <p>A {@code null} input String returns {@code null}.</p>
    6737     *
    6738     * <pre>
    6739     * StringUtils.lowerCase(null)  = null
    6740     * StringUtils.lowerCase("")    = ""
    6741     * StringUtils.lowerCase("aBc") = "abc"
    6742     * </pre>
    6743     *
    6744     * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
    6745     * the result of this method is affected by the current locale.
    6746     * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    6747     * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    6748     *
    6749     * @param str  the String to lower case, may be null
    6750     * @return the lower cased String, {@code null} if null String input
    6751     */
    6752    public static String lowerCase(final String str) {
    6753        if (str == null) {
    6754            return null;
    6755        }
    6756        return str.toLowerCase();
    6757    }
    6758
    6759    /**
    6760     * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
    6761     *
    6762     * <p>A {@code null} input String returns {@code null}.</p>
    6763     *
    6764     * <pre>
    6765     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    6766     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    6767     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    6768     * </pre>
    6769     *
    6770     * @param str  the String to lower case, may be null
    6771     * @param locale  the locale that defines the case transformation rules, must not be null
    6772     * @return the lower cased String, {@code null} if null String input
    6773     * @since 2.5
    6774     */
    6775    public static String lowerCase(final String str, final Locale locale) {
    6776        if (str == null) {
    6777            return null;
    6778        }
    6779        return str.toLowerCase(locale);
    6780    }
    6781
    6782    /**
    6783     * <p>Capitalizes a String changing the first character to title case as
    6784     * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
    6785     *
    6786     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
    6787     * A {@code null} input String returns {@code null}.</p>
    6788     *
    6789     * <pre>
    6790     * StringUtils.capitalize(null)  = null
    6791     * StringUtils.capitalize("")    = ""
    6792     * StringUtils.capitalize("cat") = "Cat"
    6793     * StringUtils.capitalize("cAt") = "CAt"
    6794     * StringUtils.capitalize("'cat'") = "'cat'"
    6795     * </pre>
    6796     *
    6797     * @param str the String to capitalize, may be null
    6798     * @return the capitalized String, {@code null} if null String input
    6799     * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
    6800     * @see #uncapitalize(String)
    6801     * @since 2.0
    6802     */
    6803    public static String capitalize(final String str) {
    6804        int strLen;
    6805        if (str == null || (strLen = str.length()) == 0) {
    6806            return str;
    6807        }
    6808
    6809        final int firstCodepoint = str.codePointAt(0);
    6810        final int newCodePoint = Character.toTitleCase(firstCodepoint);
    6811        if (firstCodepoint == newCodePoint) {
    6812            // already capitalized
    6813            return str;
    6814        }
    6815
    6816        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
    6817        int outOffset = 0;
    6818        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
    6819        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
    6820            final int codepoint = str.codePointAt(inOffset);
    6821            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
    6822            inOffset += Character.charCount(codepoint);
    6823         }
    6824        return new String(newCodePoints, 0, outOffset);
    6825    }
    6826
    6827    /**
    6828     * <p>Uncapitalizes a String, changing the first character to lower case as
    6829     * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
    6830     *
    6831     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
    6832     * A {@code null} input String returns {@code null}.</p>
    6833     *
    6834     * <pre>
    6835     * StringUtils.uncapitalize(null)  = null
    6836     * StringUtils.uncapitalize("")    = ""
    6837     * StringUtils.uncapitalize("cat") = "cat"
    6838     * StringUtils.uncapitalize("Cat") = "cat"
    6839     * StringUtils.uncapitalize("CAT") = "cAT"
    6840     * </pre>
    6841     *
    6842     * @param str the String to uncapitalize, may be null
    6843     * @return the uncapitalized String, {@code null} if null String input
    6844     * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
    6845     * @see #capitalize(String)
    6846     * @since 2.0
    6847     */
    6848    public static String uncapitalize(final String str) {
    6849        int strLen;
    6850        if (str == null || (strLen = str.length()) == 0) {
    6851            return str;
    6852        }
    6853
    6854        final int firstCodepoint = str.codePointAt(0);
    6855        final int newCodePoint = Character.toLowerCase(firstCodepoint);
    6856        if (firstCodepoint == newCodePoint) {
    6857            // already capitalized
    6858            return str;
    6859        }
    6860
    6861        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
    6862        int outOffset = 0;
    6863        newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
    6864        for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
    6865            final int codepoint = str.codePointAt(inOffset);
    6866            newCodePoints[outOffset++] = codepoint; // copy the remaining ones
    6867            inOffset += Character.charCount(codepoint);
    6868         }
    6869        return new String(newCodePoints, 0, outOffset);
    6870    }
    6871
    6872    /**
    6873     * <p>Swaps the case of a String changing upper and title case to
    6874     * lower case, and lower case to upper case.</p>
    6875     *
    6876     * <ul>
    6877     *  <li>Upper case character converts to Lower case</li>
    6878     *  <li>Title case character converts to Lower case</li>
    6879     *  <li>Lower case character converts to Upper case</li>
    6880     * </ul>
    6881     *
    6882     * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
    6883     * A {@code null} input String returns {@code null}.</p>
    6884     *
    6885     * <pre>
    6886     * StringUtils.swapCase(null)                 = null
    6887     * StringUtils.swapCase("")                   = ""
    6888     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    6889     * </pre>
    6890     *
    6891     * <p>NOTE: This method changed in Lang version 2.0.
    6892     * It no longer performs a word based algorithm.
    6893     * If you only use ASCII, you will notice no change.
    6894     * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
    6895     *
    6896     * @param str  the String to swap case, may be null
    6897     * @return the changed String, {@code null} if null String input
    6898     */
    6899    public static String swapCase(final String str) {
    6900        if (isEmpty(str)) {
    6901            return str;
    6902        }
    6903
    6904        final int strLen = str.length();
    6905        final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
    6906        int outOffset = 0;
    6907        for (int i = 0; i < strLen; ) {
    6908            final int oldCodepoint = str.codePointAt(i);
    6909            final int newCodePoint;
    6910            if (Character.isUpperCase(oldCodepoint)) {
    6911                newCodePoint = Character.toLowerCase(oldCodepoint);
    6912            } else if (Character.isTitleCase(oldCodepoint)) {
    6913                newCodePoint = Character.toLowerCase(oldCodepoint);
    6914            } else if (Character.isLowerCase(oldCodepoint)) {
    6915                newCodePoint = Character.toUpperCase(oldCodepoint);
    6916            } else {
    6917                newCodePoint = oldCodepoint;
    6918            }
    6919            newCodePoints[outOffset++] = newCodePoint;
    6920            i += Character.charCount(newCodePoint);
    6921         }
    6922        return new String(newCodePoints, 0, outOffset);
    6923    }
    6924
    6925    // Count matches
    6926    //-----------------------------------------------------------------------
    6927    /**
    6928     * <p>Counts how many times the substring appears in the larger string.</p>
    6929     *
    6930     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    6931     *
    6932     * <pre>
    6933     * StringUtils.countMatches(null, *)       = 0
    6934     * StringUtils.countMatches("", *)         = 0
    6935     * StringUtils.countMatches("abba", null)  = 0
    6936     * StringUtils.countMatches("abba", "")    = 0
    6937     * StringUtils.countMatches("abba", "a")   = 2
    6938     * StringUtils.countMatches("abba", "ab")  = 1
    6939     * StringUtils.countMatches("abba", "xxx") = 0
    6940     * </pre>
    6941     *
    6942     * @param str  the CharSequence to check, may be null
    6943     * @param sub  the substring to count, may be null
    6944     * @return the number of occurrences, 0 if either CharSequence is {@code null}
    6945     * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
    6946     */
    6947    public static int countMatches(final CharSequence str, final CharSequence sub) {
    6948        if (isEmpty(str) || isEmpty(sub)) {
    6949            return 0;
    6950        }
    6951        int count = 0;
    6952        int idx = 0;
    6953        while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
    6954            count++;
    6955            idx += sub.length();
    6956        }
    6957        return count;
    6958    }
    6959
    6960    /**
    6961     * <p>Counts how many times the char appears in the given string.</p>
    6962     *
    6963     * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
    6964     *
    6965     * <pre>
    6966     * StringUtils.countMatches(null, *)       = 0
    6967     * StringUtils.countMatches("", *)         = 0
    6968     * StringUtils.countMatches("abba", 0)  = 0
    6969     * StringUtils.countMatches("abba", 'a')   = 2
    6970     * StringUtils.countMatches("abba", 'b')  = 2
    6971     * StringUtils.countMatches("abba", 'x') = 0
    6972     * </pre>
    6973     *
    6974     * @param str  the CharSequence to check, may be null
    6975     * @param ch  the char to count
    6976     * @return the number of occurrences, 0 if the CharSequence is {@code null}
    6977     * @since 3.4
    6978     */
    6979    public static int countMatches(final CharSequence str, final char ch) {
    6980        if (isEmpty(str)) {
    6981            return 0;
    6982        }
    6983        int count = 0;
    6984        // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
    6985        for (int i = 0; i < str.length(); i++) {
    6986            if (ch == str.charAt(i)) {
    6987                count++;
    6988            }
    6989        }
    6990        return count;
    6991    }
    6992
    6993    // Character Tests
    6994    //-----------------------------------------------------------------------
    6995    /**
    6996     * <p>Checks if the CharSequence contains only Unicode letters.</p>
    6997     *
    6998     * <p>{@code null} will return {@code false}.
    6999     * An empty CharSequence (length()=0) will return {@code false}.</p>
    7000     *
    7001     * <pre>
    7002     * StringUtils.isAlpha(null)   = false
    7003     * StringUtils.isAlpha("")     = false
    7004     * StringUtils.isAlpha("  ")   = false
    7005     * StringUtils.isAlpha("abc")  = true
    7006     * StringUtils.isAlpha("ab2c") = false
    7007     * StringUtils.isAlpha("ab-c") = false
    7008     * </pre>
    7009     *
    7010     * @param cs  the CharSequence to check, may be null
    7011     * @return {@code true} if only contains letters, and is non-null
    7012     * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    7013     * @since 3.0 Changed "" to return false and not true
    7014     */
    7015    public static boolean isAlpha(final CharSequence cs) {
    7016        if (isEmpty(cs)) {
    7017            return false;
    7018        }
    7019        final int sz = cs.length();
    7020        for (int i = 0; i < sz; i++) {
    7021            if (!Character.isLetter(cs.charAt(i))) {
    7022                return false;
    7023            }
    7024        }
    7025        return true;
    7026    }
    7027
    7028    /**
    7029     * <p>Checks if the CharSequence contains only Unicode letters and
    7030     * space (' ').</p>
    7031     *
    7032     * <p>{@code null} will return {@code false}
    7033     * An empty CharSequence (length()=0) will return {@code true}.</p>
    7034     *
    7035     * <pre>
    7036     * StringUtils.isAlphaSpace(null)   = false
    7037     * StringUtils.isAlphaSpace("")     = true
    7038     * StringUtils.isAlphaSpace("  ")   = true
    7039     * StringUtils.isAlphaSpace("abc")  = true
    7040     * StringUtils.isAlphaSpace("ab c") = true
    7041     * StringUtils.isAlphaSpace("ab2c") = false
    7042     * StringUtils.isAlphaSpace("ab-c") = false
    7043     * </pre>
    7044     *
    7045     * @param cs  the CharSequence to check, may be null
    7046     * @return {@code true} if only contains letters and space,
    7047     *  and is non-null
    7048     * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    7049     */
    7050    public static boolean isAlphaSpace(final CharSequence cs) {
    7051        if (cs == null) {
    7052            return false;
    7053        }
    7054        final int sz = cs.length();
    7055        for (int i = 0; i < sz; i++) {
    7056            if (!Character.isLetter(cs.charAt(i)) && cs.charAt(i) != ' ') {
    7057                return false;
    7058            }
    7059        }
    7060        return true;
    7061    }
    7062
    7063    /**
    7064     * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
    7065     *
    7066     * <p>{@code null} will return {@code false}.
    7067     * An empty CharSequence (length()=0) will return {@code false}.</p>
    7068     *
    7069     * <pre>
    7070     * StringUtils.isAlphanumeric(null)   = false
    7071     * StringUtils.isAlphanumeric("")     = false
    7072     * StringUtils.isAlphanumeric("  ")   = false
    7073     * StringUtils.isAlphanumeric("abc")  = true
    7074     * StringUtils.isAlphanumeric("ab c") = false
    7075     * StringUtils.isAlphanumeric("ab2c") = true
    7076     * StringUtils.isAlphanumeric("ab-c") = false
    7077     * </pre>
    7078     *
    7079     * @param cs  the CharSequence to check, may be null
    7080     * @return {@code true} if only contains letters or digits,
    7081     *  and is non-null
    7082     * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    7083     * @since 3.0 Changed "" to return false and not true
    7084     */
    7085    public static boolean isAlphanumeric(final CharSequence cs) {
    7086        if (isEmpty(cs)) {
    7087            return false;
    7088        }
    7089        final int sz = cs.length();
    7090        for (int i = 0; i < sz; i++) {
    7091            if (!Character.isLetterOrDigit(cs.charAt(i))) {
    7092                return false;
    7093            }
    7094        }
    7095        return true;
    7096    }
    7097
    7098    /**
    7099     * <p>Checks if the CharSequence contains only Unicode letters, digits
    7100     * or space ({@code ' '}).</p>
    7101     *
    7102     * <p>{@code null} will return {@code false}.
    7103     * An empty CharSequence (length()=0) will return {@code true}.</p>
    7104     *
    7105     * <pre>
    7106     * StringUtils.isAlphanumericSpace(null)   = false
    7107     * StringUtils.isAlphanumericSpace("")     = true
    7108     * StringUtils.isAlphanumericSpace("  ")   = true
    7109     * StringUtils.isAlphanumericSpace("abc")  = true
    7110     * StringUtils.isAlphanumericSpace("ab c") = true
    7111     * StringUtils.isAlphanumericSpace("ab2c") = true
    7112     * StringUtils.isAlphanumericSpace("ab-c") = false
    7113     * </pre>
    7114     *
    7115     * @param cs  the CharSequence to check, may be null
    7116     * @return {@code true} if only contains letters, digits or space,
    7117     *  and is non-null
    7118     * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    7119     */
    7120    public static boolean isAlphanumericSpace(final CharSequence cs) {
    7121        if (cs == null) {
    7122            return false;
    7123        }
    7124        final int sz = cs.length();
    7125        for (int i = 0; i < sz; i++) {
    7126            if (!Character.isLetterOrDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
    7127                return false;
    7128            }
    7129        }
    7130        return true;
    7131    }
    7132
    7133    /**
    7134     * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
    7135     *
    7136     * <p>{@code null} will return {@code false}.
    7137     * An empty CharSequence (length()=0) will return {@code true}.</p>
    7138     *
    7139     * <pre>
    7140     * StringUtils.isAsciiPrintable(null)     = false
    7141     * StringUtils.isAsciiPrintable("")       = true
    7142     * StringUtils.isAsciiPrintable(" ")      = true
    7143     * StringUtils.isAsciiPrintable("Ceki")   = true
    7144     * StringUtils.isAsciiPrintable("ab2c")   = true
    7145     * StringUtils.isAsciiPrintable("!ab-c~") = true
    7146     * StringUtils.isAsciiPrintable("\u0020") = true
    7147     * StringUtils.isAsciiPrintable("\u0021") = true
    7148     * StringUtils.isAsciiPrintable("\u007e") = true
    7149     * StringUtils.isAsciiPrintable("\u007f") = false
    7150     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    7151     * </pre>
    7152     *
    7153     * @param cs the CharSequence to check, may be null
    7154     * @return {@code true} if every character is in the range
    7155     *  32 thru 126
    7156     * @since 2.1
    7157     * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    7158     */
    7159    public static boolean isAsciiPrintable(final CharSequence cs) {
    7160        if (cs == null) {
    7161            return false;
    7162        }
    7163        final int sz = cs.length();
    7164        for (int i = 0; i < sz; i++) {
    7165            if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
    7166                return false;
    7167            }
    7168        }
    7169        return true;
    7170    }
    7171
    7172    /**
    7173     * <p>Checks if the CharSequence contains only Unicode digits.
    7174     * A decimal point is not a Unicode digit and returns false.</p>
    7175     *
    7176     * <p>{@code null} will return {@code false}.
    7177     * An empty CharSequence (length()=0) will return {@code false}.</p>
    7178     *
    7179     * <p>Note that the method does not allow for a leading sign, either positive or negative.
    7180     * Also, if a String passes the numeric test, it may still generate a NumberFormatException
    7181     * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
    7182     * for int or long respectively.</p>
    7183     *
    7184     * <pre>
    7185     * StringUtils.isNumeric(null)   = false
    7186     * StringUtils.isNumeric("")     = false
    7187     * StringUtils.isNumeric("  ")   = false
    7188     * StringUtils.isNumeric("123")  = true
    7189     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    7190     * StringUtils.isNumeric("12 3") = false
    7191     * StringUtils.isNumeric("ab2c") = false
    7192     * StringUtils.isNumeric("12-3") = false
    7193     * StringUtils.isNumeric("12.3") = false
    7194     * StringUtils.isNumeric("-123") = false
    7195     * StringUtils.isNumeric("+123") = false
    7196     * </pre>
    7197     *
    7198     * @param cs  the CharSequence to check, may be null
    7199     * @return {@code true} if only contains digits, and is non-null
    7200     * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    7201     * @since 3.0 Changed "" to return false and not true
    7202     */
    7203    public static boolean isNumeric(final CharSequence cs) {
    7204        if (isEmpty(cs)) {
    7205            return false;
    7206        }
    7207        final int sz = cs.length();
    7208        for (int i = 0; i < sz; i++) {
    7209            if (!Character.isDigit(cs.charAt(i))) {
    7210                return false;
    7211            }
    7212        }
    7213        return true;
    7214    }
    7215
    7216    /**
    7217     * <p>Checks if the CharSequence contains only Unicode digits or space
    7218     * ({@code ' '}).
    7219     * A decimal point is not a Unicode digit and returns false.</p>
    7220     *
    7221     * <p>{@code null} will return {@code false}.
    7222     * An empty CharSequence (length()=0) will return {@code true}.</p>
    7223     *
    7224     * <pre>
    7225     * StringUtils.isNumericSpace(null)   = false
    7226     * StringUtils.isNumericSpace("")     = true
    7227     * StringUtils.isNumericSpace("  ")   = true
    7228     * StringUtils.isNumericSpace("123")  = true
    7229     * StringUtils.isNumericSpace("12 3") = true
    7230     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
    7231     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
    7232     * StringUtils.isNumericSpace("ab2c") = false
    7233     * StringUtils.isNumericSpace("12-3") = false
    7234     * StringUtils.isNumericSpace("12.3") = false
    7235     * </pre>
    7236     *
    7237     * @param cs  the CharSequence to check, may be null
    7238     * @return {@code true} if only contains digits or space,
    7239     *  and is non-null
    7240     * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    7241     */
    7242    public static boolean isNumericSpace(final CharSequence cs) {
    7243        if (cs == null) {
    7244            return false;
    7245        }
    7246        final int sz = cs.length();
    7247        for (int i = 0; i < sz; i++) {
    7248            if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
    7249                return false;
    7250            }
    7251        }
    7252        return true;
    7253    }
    7254
    7255    /**
    7256     * <p>Checks if a String {@code str} contains Unicode digits,
    7257     * if yes then concatenate all the digits in {@code str} and return it as a String.</p>
    7258     *
    7259     * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
    7260     *
    7261     * <pre>
    7262     * StringUtils.getDigits(null)  = null
    7263     * StringUtils.getDigits("")    = ""
    7264     * StringUtils.getDigits("abc") = ""
    7265     * StringUtils.getDigits("1000$") = "1000"
    7266     * StringUtils.getDigits("1123~45") = "112345"
    7267     * StringUtils.getDigits("(541) 754-3010") = "5417543010"
    7268     * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
    7269     * </pre>
    7270     *
    7271     * @param str the String to extract digits from, may be null
    7272     * @return String with only digits,
    7273     *           or an empty ("") String if no digits found,
    7274     *           or {@code null} String if {@code str} is null
    7275     * @since 3.6
    7276     */
    7277    public static String getDigits(final String str) {
    7278        if (isEmpty(str)) {
    7279            return str;
    7280        }
    7281        final int sz = str.length();
    7282        final StringBuilder strDigits = new StringBuilder(sz);
    7283        for (int i = 0; i < sz; i++) {
    7284            final char tempChar = str.charAt(i);
    7285            if (Character.isDigit(tempChar)) {
    7286                strDigits.append(tempChar);
    7287            }
    7288        }
    7289        return strDigits.toString();
    7290    }
    7291
    7292    /**
    7293     * <p>Checks if the CharSequence contains only whitespace.</p>
    7294     *
    7295     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7296     *
    7297     * <p>{@code null} will return {@code false}.
    7298     * An empty CharSequence (length()=0) will return {@code true}.</p>
    7299     *
    7300     * <pre>
    7301     * StringUtils.isWhitespace(null)   = false
    7302     * StringUtils.isWhitespace("")     = true
    7303     * StringUtils.isWhitespace("  ")   = true
    7304     * StringUtils.isWhitespace("abc")  = false
    7305     * StringUtils.isWhitespace("ab2c") = false
    7306     * StringUtils.isWhitespace("ab-c") = false
    7307     * </pre>
    7308     *
    7309     * @param cs  the CharSequence to check, may be null
    7310     * @return {@code true} if only contains whitespace, and is non-null
    7311     * @since 2.0
    7312     * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    7313     */
    7314    public static boolean isWhitespace(final CharSequence cs) {
    7315        if (cs == null) {
    7316            return false;
    7317        }
    7318        final int sz = cs.length();
    7319        for (int i = 0; i < sz; i++) {
    7320            if (!Character.isWhitespace(cs.charAt(i))) {
    7321                return false;
    7322            }
    7323        }
    7324        return true;
    7325    }
    7326
    7327    /**
    7328     * <p>Checks if the CharSequence contains only lowercase characters.</p>
    7329     *
    7330     * <p>{@code null} will return {@code false}.
    7331     * An empty CharSequence (length()=0) will return {@code false}.</p>
    7332     *
    7333     * <pre>
    7334     * StringUtils.isAllLowerCase(null)   = false
    7335     * StringUtils.isAllLowerCase("")     = false
    7336     * StringUtils.isAllLowerCase("  ")   = false
    7337     * StringUtils.isAllLowerCase("abc")  = true
    7338     * StringUtils.isAllLowerCase("abC")  = false
    7339     * StringUtils.isAllLowerCase("ab c") = false
    7340     * StringUtils.isAllLowerCase("ab1c") = false
    7341     * StringUtils.isAllLowerCase("ab/c") = false
    7342     * </pre>
    7343     *
    7344     * @param cs  the CharSequence to check, may be null
    7345     * @return {@code true} if only contains lowercase characters, and is non-null
    7346     * @since 2.5
    7347     * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    7348     */
    7349    public static boolean isAllLowerCase(final CharSequence cs) {
    7350        if (cs == null || isEmpty(cs)) {
    7351            return false;
    7352        }
    7353        final int sz = cs.length();
    7354        for (int i = 0; i < sz; i++) {
    7355            if (!Character.isLowerCase(cs.charAt(i))) {
    7356                return false;
    7357            }
    7358        }
    7359        return true;
    7360    }
    7361
    7362    /**
    7363     * <p>Checks if the CharSequence contains only uppercase characters.</p>
    7364     *
    7365     * <p>{@code null} will return {@code false}.
    7366     * An empty String (length()=0) will return {@code false}.</p>
    7367     *
    7368     * <pre>
    7369     * StringUtils.isAllUpperCase(null)   = false
    7370     * StringUtils.isAllUpperCase("")     = false
    7371     * StringUtils.isAllUpperCase("  ")   = false
    7372     * StringUtils.isAllUpperCase("ABC")  = true
    7373     * StringUtils.isAllUpperCase("aBC")  = false
    7374     * StringUtils.isAllUpperCase("A C")  = false
    7375     * StringUtils.isAllUpperCase("A1C")  = false
    7376     * StringUtils.isAllUpperCase("A/C")  = false
    7377     * </pre>
    7378     *
    7379     * @param cs the CharSequence to check, may be null
    7380     * @return {@code true} if only contains uppercase characters, and is non-null
    7381     * @since 2.5
    7382     * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    7383     */
    7384    public static boolean isAllUpperCase(final CharSequence cs) {
    7385        if (cs == null || isEmpty(cs)) {
    7386            return false;
    7387        }
    7388        final int sz = cs.length();
    7389        for (int i = 0; i < sz; i++) {
    7390            if (!Character.isUpperCase(cs.charAt(i))) {
    7391                return false;
    7392            }
    7393        }
    7394        return true;
    7395    }
    7396
    7397    /**
    7398     * <p>Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.</p>
    7399     *
    7400     * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
    7401     * {@code false}.</p>
    7402     *
    7403     * <pre>
    7404     * StringUtils.isMixedCase(null)    = false
    7405     * StringUtils.isMixedCase("")      = false
    7406     * StringUtils.isMixedCase("ABC")   = false
    7407     * StringUtils.isMixedCase("abc")   = false
    7408     * StringUtils.isMixedCase("aBc")   = true
    7409     * StringUtils.isMixedCase("A c")   = true
    7410     * StringUtils.isMixedCase("A1c")   = true
    7411     * StringUtils.isMixedCase("a/C")   = true
    7412     * StringUtils.isMixedCase("aC\t")  = true
    7413     * </pre>
    7414     *
    7415     * @param cs the CharSequence to check, may be null
    7416     * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
    7417     * @since 3.5
    7418     */
    7419    public static boolean isMixedCase(final CharSequence cs) {
    7420        if (isEmpty(cs) || cs.length() == 1) {
    7421            return false;
    7422        }
    7423        boolean containsUppercase = false;
    7424        boolean containsLowercase = false;
    7425        final int sz = cs.length();
    7426        for (int i = 0; i < sz; i++) {
    7427            if (containsUppercase && containsLowercase) {
    7428                return true;
    7429            } else if (Character.isUpperCase(cs.charAt(i))) {
    7430                containsUppercase = true;
    7431            } else if (Character.isLowerCase(cs.charAt(i))) {
    7432                containsLowercase = true;
    7433            }
    7434        }
    7435        return containsUppercase && containsLowercase;
    7436    }
    7437
    7438    // Defaults
    7439    //-----------------------------------------------------------------------
    7440    /**
    7441     * <p>Returns either the passed in String,
    7442     * or if the String is {@code null}, an empty String ("").</p>
    7443     *
    7444     * <pre>
    7445     * StringUtils.defaultString(null)  = ""
    7446     * StringUtils.defaultString("")    = ""
    7447     * StringUtils.defaultString("bat") = "bat"
    7448     * </pre>
    7449     *
    7450     * @see ObjectUtils#toString(Object)
    7451     * @see String#valueOf(Object)
    7452     * @param str  the String to check, may be null
    7453     * @return the passed in String, or the empty String if it
    7454     *  was {@code null}
    7455     */
    7456    public static String defaultString(final String str) {
    7457        return defaultString(str, EMPTY);
    7458    }
    7459
    7460    /**
    7461     * <p>Returns either the passed in String, or if the String is
    7462     * {@code null}, the value of {@code defaultStr}.</p>
    7463     *
    7464     * <pre>
    7465     * StringUtils.defaultString(null, "NULL")  = "NULL"
    7466     * StringUtils.defaultString("", "NULL")    = ""
    7467     * StringUtils.defaultString("bat", "NULL") = "bat"
    7468     * </pre>
    7469     *
    7470     * @see ObjectUtils#toString(Object,String)
    7471     * @see String#valueOf(Object)
    7472     * @param str  the String to check, may be null
    7473     * @param defaultStr  the default String to return
    7474     *  if the input is {@code null}, may be null
    7475     * @return the passed in String, or the default if it was {@code null}
    7476     */
    7477    public static String defaultString(final String str, final String defaultStr) {
    7478        return str == null ? defaultStr : str;
    7479    }
    7480
    7481    /**
    7482     * <p>Returns the first value in the array which is not empty (""),
    7483     * {@code null} or whitespace only.</p>
    7484     *
    7485     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7486     *
    7487     * <p>If all values are blank or the array is {@code null}
    7488     * or empty then {@code null} is returned.</p>
    7489     *
    7490     * <pre>
    7491     * StringUtils.firstNonBlank(null, null, null)     = null
    7492     * StringUtils.firstNonBlank(null, "", " ")        = null
    7493     * StringUtils.firstNonBlank("abc")                = "abc"
    7494     * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
    7495     * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
    7496     * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
    7497     * StringUtils.firstNonBlank()                     = null
    7498     * </pre>
    7499     *
    7500     * @param <T> the specific kind of CharSequence
    7501     * @param values  the values to test, may be {@code null} or empty
    7502     * @return the first value from {@code values} which is not blank,
    7503     *  or {@code null} if there are no non-blank values
    7504     * @since 3.8
    7505     */
    7506    @SafeVarargs
    7507    public static <T extends CharSequence> T firstNonBlank(final T... values) {
    7508        if (values != null) {
    7509            for (final T val : values) {
    7510                if (isNotBlank(val)) {
    7511                    return val;
    7512                }
    7513            }
    7514        }
    7515        return null;
    7516    }
    7517
    7518    /**
    7519     * <p>Returns the first value in the array which is not empty.</p>
    7520     *
    7521     * <p>If all values are empty or the array is {@code null}
    7522     * or empty then {@code null} is returned.</p>
    7523     *
    7524     * <pre>
    7525     * StringUtils.firstNonEmpty(null, null, null)   = null
    7526     * StringUtils.firstNonEmpty(null, null, "")     = null
    7527     * StringUtils.firstNonEmpty(null, "", " ")      = " "
    7528     * StringUtils.firstNonEmpty("abc")              = "abc"
    7529     * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
    7530     * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
    7531     * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
    7532     * StringUtils.firstNonEmpty()                   = null
    7533     * </pre>
    7534     *
    7535     * @param <T> the specific kind of CharSequence
    7536     * @param values  the values to test, may be {@code null} or empty
    7537     * @return the first value from {@code values} which is not empty,
    7538     *  or {@code null} if there are no non-empty values
    7539     * @since 3.8
    7540     */
    7541    @SafeVarargs
    7542    public static <T extends CharSequence> T firstNonEmpty(final T... values) {
    7543        if (values != null) {
    7544            for (final T val : values) {
    7545                if (isNotEmpty(val)) {
    7546                    return val;
    7547                }
    7548            }
    7549        }
    7550        return null;
    7551    }
    7552
    7553    /**
    7554     * <p>Returns either the passed in CharSequence, or if the CharSequence is
    7555     * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
    7556     *
    7557     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    7558     *
    7559     * <pre>
    7560     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
    7561     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
    7562     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
    7563     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
    7564     * StringUtils.defaultIfBlank("", null)      = null
    7565     * </pre>
    7566     * @param <T> the specific kind of CharSequence
    7567     * @param str the CharSequence to check, may be null
    7568     * @param defaultStr  the default CharSequence to return
    7569     *  if the input is whitespace, empty ("") or {@code null}, may be null
    7570     * @return the passed in CharSequence, or the default
    7571     * @see StringUtils#defaultString(String, String)
    7572     */
    7573    public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
    7574        return isBlank(str) ? defaultStr : str;
    7575    }
    7576
    7577    /**
    7578     * <p>Returns either the passed in CharSequence, or if the CharSequence is
    7579     * empty or {@code null}, the value of {@code defaultStr}.</p>
    7580     *
    7581     * <pre>
    7582     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    7583     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    7584     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
    7585     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    7586     * StringUtils.defaultIfEmpty("", null)      = null
    7587     * </pre>
    7588     * @param <T> the specific kind of CharSequence
    7589     * @param str  the CharSequence to check, may be null
    7590     * @param defaultStr  the default CharSequence to return
    7591     *  if the input is empty ("") or {@code null}, may be null
    7592     * @return the passed in CharSequence, or the default
    7593     * @see StringUtils#defaultString(String, String)
    7594     */
    7595    public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
    7596        return isEmpty(str) ? defaultStr : str;
    7597    }
    7598
    7599    // Rotating (circular shift)
    7600    //-----------------------------------------------------------------------
    7601    /**
    7602     * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
    7603     * <ul>
    7604     *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
    7605     *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
    7606     * </ul>
    7607     *
    7608     * <pre>
    7609     * StringUtils.rotate(null, *)        = null
    7610     * StringUtils.rotate("", *)          = ""
    7611     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
    7612     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
    7613     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
    7614     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
    7615     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
    7616     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
    7617     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
    7618     * </pre>
    7619     *
    7620     * @param str  the String to rotate, may be null
    7621     * @param shift  number of time to shift (positive : right shift, negative : left shift)
    7622     * @return the rotated String,
    7623     *          or the original String if {@code shift == 0},
    7624     *          or {@code null} if null String input
    7625     * @since 3.5
    7626     */
    7627    public static String rotate(final String str, final int shift) {
    7628        if (str == null) {
    7629            return null;
    7630        }
    7631
    7632        final int strLen = str.length();
    7633        if (shift == 0 || strLen == 0 || shift % strLen == 0) {
    7634            return str;
    7635        }
    7636
    7637        final StringBuilder builder = new StringBuilder(strLen);
    7638        final int offset = - (shift % strLen);
    7639        builder.append(substring(str, offset));
    7640        builder.append(substring(str, 0, offset));
    7641        return builder.toString();
    7642    }
    7643
    7644    // Reversing
    7645    //-----------------------------------------------------------------------
    7646    /**
    7647     * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
    7648     *
    7649     * <p>A {@code null} String returns {@code null}.</p>
    7650     *
    7651     * <pre>
    7652     * StringUtils.reverse(null)  = null
    7653     * StringUtils.reverse("")    = ""
    7654     * StringUtils.reverse("bat") = "tab"
    7655     * </pre>
    7656     *
    7657     * @param str  the String to reverse, may be null
    7658     * @return the reversed String, {@code null} if null String input
    7659     */
    7660    public static String reverse(final String str) {
    7661        if (str == null) {
    7662            return null;
    7663        }
    7664        return new StringBuilder(str).reverse().toString();
    7665    }
    7666
    7667    /**
    7668     * <p>Reverses a String that is delimited by a specific character.</p>
    7669     *
    7670     * <p>The Strings between the delimiters are not reversed.
    7671     * Thus java.lang.String becomes String.lang.java (if the delimiter
    7672     * is {@code '.'}).</p>
    7673     *
    7674     * <pre>
    7675     * StringUtils.reverseDelimited(null, *)      = null
    7676     * StringUtils.reverseDelimited("", *)        = ""
    7677     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    7678     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    7679     * </pre>
    7680     *
    7681     * @param str  the String to reverse, may be null
    7682     * @param separatorChar  the separator character to use
    7683     * @return the reversed String, {@code null} if null String input
    7684     * @since 2.0
    7685     */
    7686    public static String reverseDelimited(final String str, final char separatorChar) {
    7687        if (str == null) {
    7688            return null;
    7689        }
    7690        // could implement manually, but simple way is to reuse other,
    7691        // probably slower, methods.
    7692        final String[] strs = split(str, separatorChar);
    7693        ArrayUtils.reverse(strs);
    7694        return join(strs, separatorChar);
    7695    }
    7696
    7697    // Abbreviating
    7698    //-----------------------------------------------------------------------
    7699    /**
    7700     * <p>Abbreviates a String using ellipses. This will turn
    7701     * "Now is the time for all good men" into "Now is the time for..."</p>
    7702     *
    7703     * <p>Specifically:</p>
    7704     * <ul>
    7705     *   <li>If the number of characters in {@code str} is less than or equal to
    7706     *       {@code maxWidth}, return {@code str}.</li>
    7707     *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
    7708     *   <li>If {@code maxWidth} is less than {@code 4}, throw an
    7709     *       {@code IllegalArgumentException}.</li>
    7710     *   <li>In no case will it return a String of length greater than
    7711     *       {@code maxWidth}.</li>
    7712     * </ul>
    7713     *
    7714     * <pre>
    7715     * StringUtils.abbreviate(null, *)      = null
    7716     * StringUtils.abbreviate("", 4)        = ""
    7717     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
    7718     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
    7719     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
    7720     * StringUtils.abbreviate("abcdefg", 4) = "a..."
    7721     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
    7722     * </pre>
    7723     *
    7724     * @param str  the String to check, may be null
    7725     * @param maxWidth  maximum length of result String, must be at least 4
    7726     * @return abbreviated String, {@code null} if null String input
    7727     * @throws IllegalArgumentException if the width is too small
    7728     * @since 2.0
    7729     */
    7730    public static String abbreviate(final String str, final int maxWidth) {
    7731        final String defaultAbbrevMarker = "...";
    7732        return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
    7733    }
    7734
    7735    /**
    7736     * <p>Abbreviates a String using ellipses. This will turn
    7737     * "Now is the time for all good men" into "...is the time for..."</p>
    7738     *
    7739     * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
    7740     * a "left edge" offset.  Note that this left edge is not necessarily going to
    7741     * be the leftmost character in the result, or the first character following the
    7742     * ellipses, but it will appear somewhere in the result.
    7743     *
    7744     * <p>In no case will it return a String of length greater than
    7745     * {@code maxWidth}.</p>
    7746     *
    7747     * <pre>
    7748     * StringUtils.abbreviate(null, *, *)                = null
    7749     * StringUtils.abbreviate("", 0, 4)                  = ""
    7750     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
    7751     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
    7752     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
    7753     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
    7754     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
    7755     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
    7756     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
    7757     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
    7758     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
    7759     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
    7760     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
    7761     * </pre>
    7762     *
    7763     * @param str  the String to check, may be null
    7764     * @param offset  left edge of source String
    7765     * @param maxWidth  maximum length of result String, must be at least 4
    7766     * @return abbreviated String, {@code null} if null String input
    7767     * @throws IllegalArgumentException if the width is too small
    7768     * @since 2.0
    7769     */
    7770    public static String abbreviate(final String str, final int offset, final int maxWidth) {
    7771        final String defaultAbbrevMarker = "...";
    7772        return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
    7773    }
    7774
    7775    /**
    7776     * <p>Abbreviates a String using another given String as replacement marker. This will turn
    7777     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
    7778     * as the replacement marker.</p>
    7779     *
    7780     * <p>Specifically:</p>
    7781     * <ul>
    7782     *   <li>If the number of characters in {@code str} is less than or equal to
    7783     *       {@code maxWidth}, return {@code str}.</li>
    7784     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
    7785     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
    7786     *       {@code IllegalArgumentException}.</li>
    7787     *   <li>In no case will it return a String of length greater than
    7788     *       {@code maxWidth}.</li>
    7789     * </ul>
    7790     *
    7791     * <pre>
    7792     * StringUtils.abbreviate(null, "...", *)      = null
    7793     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
    7794     * StringUtils.abbreviate("", "...", 4)        = ""
    7795     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
    7796     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
    7797     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
    7798     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
    7799     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
    7800     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
    7801     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
    7802     * </pre>
    7803     *
    7804     * @param str  the String to check, may be null
    7805     * @param abbrevMarker  the String used as replacement marker
    7806     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
    7807     * @return abbreviated String, {@code null} if null String input
    7808     * @throws IllegalArgumentException if the width is too small
    7809     * @since 3.6
    7810     */
    7811    public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
    7812        return abbreviate(str, abbrevMarker, 0, maxWidth);
    7813    }
    7814
    7815    /**
    7816     * <p>Abbreviates a String using a given replacement marker. This will turn
    7817     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
    7818     * as the replacement marker.</p>
    7819     *
    7820     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
    7821     * a "left edge" offset.  Note that this left edge is not necessarily going to
    7822     * be the leftmost character in the result, or the first character following the
    7823     * replacement marker, but it will appear somewhere in the result.
    7824     *
    7825     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
    7826     *
    7827     * <pre>
    7828     * StringUtils.abbreviate(null, null, *, *)                 = null
    7829     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
    7830     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
    7831     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
    7832     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
    7833     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
    7834     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
    7835     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
    7836     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
    7837     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
    7838     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
    7839     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
    7840     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
    7841     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
    7842     * </pre>
    7843     *
    7844     * @param str  the String to check, may be null
    7845     * @param abbrevMarker  the String used as replacement marker
    7846     * @param offset  left edge of source String
    7847     * @param maxWidth  maximum length of result String, must be at least 4
    7848     * @return abbreviated String, {@code null} if null String input
    7849     * @throws IllegalArgumentException if the width is too small
    7850     * @since 3.6
    7851     */
    7852    public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
    7853        if (isEmpty(str) || isEmpty(abbrevMarker)) {
    7854            return str;
    7855        }
    7856
    7857        final int abbrevMarkerLength = abbrevMarker.length();
    7858        final int minAbbrevWidth = abbrevMarkerLength + 1;
    7859        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
    7860
    7861        if (maxWidth < minAbbrevWidth) {
    7862            throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
    7863        }
    7864        if (str.length() <= maxWidth) {
    7865            return str;
    7866        }
    7867        if (offset > str.length()) {
    7868            offset = str.length();
    7869        }
    7870        if (str.length() - offset < maxWidth - abbrevMarkerLength) {
    7871            offset = str.length() - (maxWidth - abbrevMarkerLength);
    7872        }
    7873        if (offset <= abbrevMarkerLength+1) {
    7874            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
    7875        }
    7876        if (maxWidth < minAbbrevWidthOffset) {
    7877            throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
    7878        }
    7879        if (offset + maxWidth - abbrevMarkerLength < str.length()) {
    7880            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
    7881        }
    7882        return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
    7883    }
    7884
    7885    /**
    7886     * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
    7887     * replacement String.</p>
    7888     *
    7889     * <p>This abbreviation only occurs if the following criteria is met:</p>
    7890     * <ul>
    7891     * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
    7892     * <li>The length to truncate to is less than the length of the supplied String</li>
    7893     * <li>The length to truncate to is greater than 0</li>
    7894     * <li>The abbreviated String will have enough room for the length supplied replacement String
    7895     * and the first and last characters of the supplied String for abbreviation</li>
    7896     * </ul>
    7897     * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
    7898     * </p>
    7899     *
    7900     * <pre>
    7901     * StringUtils.abbreviateMiddle(null, null, 0)      = null
    7902     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
    7903     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
    7904     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
    7905     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
    7906     * </pre>
    7907     *
    7908     * @param str  the String to abbreviate, may be null
    7909     * @param middle the String to replace the middle characters with, may be null
    7910     * @param length the length to abbreviate {@code str} to.
    7911     * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
    7912     * @since 2.5
    7913     */
    7914    public static String abbreviateMiddle(final String str, final String middle, final int length) {
    7915        if (isEmpty(str) || isEmpty(middle)) {
    7916            return str;
    7917        }
    7918
    7919        if (length >= str.length() || length < middle.length()+2) {
    7920            return str;
    7921        }
    7922
    7923        final int targetSting = length-middle.length();
    7924        final int startOffset = targetSting/2+targetSting%2;
    7925        final int endOffset = str.length()-targetSting/2;
    7926
    7927        return str.substring(0, startOffset) +
    7928            middle +
    7929            str.substring(endOffset);
    7930    }
    7931
    7932    // Difference
    7933    //-----------------------------------------------------------------------
    7934    /**
    7935     * <p>Compares two Strings, and returns the portion where they differ.
    7936     * More precisely, return the remainder of the second String,
    7937     * starting from where it's different from the first. This means that
    7938     * the difference between "abc" and "ab" is the empty String and not "c". </p>
    7939     *
    7940     * <p>For example,
    7941     * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
    7942     *
    7943     * <pre>
    7944     * StringUtils.difference(null, null) = null
    7945     * StringUtils.difference("", "") = ""
    7946     * StringUtils.difference("", "abc") = "abc"
    7947     * StringUtils.difference("abc", "") = ""
    7948     * StringUtils.difference("abc", "abc") = ""
    7949     * StringUtils.difference("abc", "ab") = ""
    7950     * StringUtils.difference("ab", "abxyz") = "xyz"
    7951     * StringUtils.difference("abcde", "abxyz") = "xyz"
    7952     * StringUtils.difference("abcde", "xyz") = "xyz"
    7953     * </pre>
    7954     *
    7955     * @param str1  the first String, may be null
    7956     * @param str2  the second String, may be null
    7957     * @return the portion of str2 where it differs from str1; returns the
    7958     * empty String if they are equal
    7959     * @see #indexOfDifference(CharSequence,CharSequence)
    7960     * @since 2.0
    7961     */
    7962    public static String difference(final String str1, final String str2) {
    7963        if (str1 == null) {
    7964            return str2;
    7965        }
    7966        if (str2 == null) {
    7967            return str1;
    7968        }
    7969        final int at = indexOfDifference(str1, str2);
    7970        if (at == INDEX_NOT_FOUND) {
    7971            return EMPTY;
    7972        }
    7973        return str2.substring(at);
    7974    }
    7975
    7976    /**
    7977     * <p>Compares two CharSequences, and returns the index at which the
    7978     * CharSequences begin to differ.</p>
    7979     *
    7980     * <p>For example,
    7981     * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
    7982     *
    7983     * <pre>
    7984     * StringUtils.indexOfDifference(null, null) = -1
    7985     * StringUtils.indexOfDifference("", "") = -1
    7986     * StringUtils.indexOfDifference("", "abc") = 0
    7987     * StringUtils.indexOfDifference("abc", "") = 0
    7988     * StringUtils.indexOfDifference("abc", "abc") = -1
    7989     * StringUtils.indexOfDifference("ab", "abxyz") = 2
    7990     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    7991     * StringUtils.indexOfDifference("abcde", "xyz") = 0
    7992     * </pre>
    7993     *
    7994     * @param cs1  the first CharSequence, may be null
    7995     * @param cs2  the second CharSequence, may be null
    7996     * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
    7997     * @since 2.0
    7998     * @since 3.0 Changed signature from indexOfDifference(String, String) to
    7999     * indexOfDifference(CharSequence, CharSequence)
    8000     */
    8001    public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
    8002        if (cs1 == cs2) {
    8003            return INDEX_NOT_FOUND;
    8004        }
    8005        if (cs1 == null || cs2 == null) {
    8006            return 0;
    8007        }
    8008        int i;
    8009        for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    8010            if (cs1.charAt(i) != cs2.charAt(i)) {
    8011                break;
    8012            }
    8013        }
    8014        if (i < cs2.length() || i < cs1.length()) {
    8015            return i;
    8016        }
    8017        return INDEX_NOT_FOUND;
    8018    }
    8019
    8020    /**
    8021     * <p>Compares all CharSequences in an array and returns the index at which the
    8022     * CharSequences begin to differ.</p>
    8023     *
    8024     * <p>For example,
    8025     * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -&gt; 7</code></p>
    8026     *
    8027     * <pre>
    8028     * StringUtils.indexOfDifference(null) = -1
    8029     * StringUtils.indexOfDifference(new String[] {}) = -1
    8030     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
    8031     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
    8032     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
    8033     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
    8034     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    8035     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    8036     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
    8037     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
    8038     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
    8039     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
    8040     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
    8041     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
    8042     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
    8043     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
    8044     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    8045     * </pre>
    8046     *
    8047     * @param css  array of CharSequences, entries may be null
    8048     * @return the index where the strings begin to differ; -1 if they are all equal
    8049     * @since 2.4
    8050     * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    8051     */
    8052    public static int indexOfDifference(final CharSequence... css) {
    8053        if (css == null || css.length <= 1) {
    8054            return INDEX_NOT_FOUND;
    8055        }
    8056        boolean anyStringNull = false;
    8057        boolean allStringsNull = true;
    8058        final int arrayLen = css.length;
    8059        int shortestStrLen = Integer.MAX_VALUE;
    8060        int longestStrLen = 0;
    8061
    8062        // find the min and max string lengths; this avoids checking to make
    8063        // sure we are not exceeding the length of the string each time through
    8064        // the bottom loop.
    8065        for (final CharSequence cs : css) {
    8066            if (cs == null) {
    8067                anyStringNull = true;
    8068                shortestStrLen = 0;
    8069            } else {
    8070                allStringsNull = false;
    8071                shortestStrLen = Math.min(cs.length(), shortestStrLen);
    8072                longestStrLen = Math.max(cs.length(), longestStrLen);
    8073            }
    8074        }
    8075
    8076        // handle lists containing all nulls or all empty strings
    8077        if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
    8078            return INDEX_NOT_FOUND;
    8079        }
    8080
    8081        // handle lists containing some nulls or some empty strings
    8082        if (shortestStrLen == 0) {
    8083            return 0;
    8084        }
    8085
    8086        // find the position with the first difference across all strings
    8087        int firstDiff = -1;
    8088        for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    8089            final char comparisonChar = css[0].charAt(stringPos);
    8090            for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    8091                if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    8092                    firstDiff = stringPos;
    8093                    break;
    8094                }
    8095            }
    8096            if (firstDiff != -1) {
    8097                break;
    8098            }
    8099        }
    8100
    8101        if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    8102            // we compared all of the characters up to the length of the
    8103            // shortest string and didn't find a match, but the string lengths
    8104            // vary, so return the length of the shortest string.
    8105            return shortestStrLen;
    8106        }
    8107        return firstDiff;
    8108    }
    8109
    8110    /**
    8111     * <p>Compares all Strings in an array and returns the initial sequence of
    8112     * characters that is common to all of them.</p>
    8113     *
    8114     * <p>For example,
    8115     * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "</code></p>
    8116     *
    8117     * <pre>
    8118     * StringUtils.getCommonPrefix(null) = ""
    8119     * StringUtils.getCommonPrefix(new String[] {}) = ""
    8120     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
    8121     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
    8122     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
    8123     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
    8124     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    8125     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    8126     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
    8127     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
    8128     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
    8129     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
    8130     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
    8131     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
    8132     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
    8133     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
    8134     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    8135     * </pre>
    8136     *
    8137     * @param strs  array of String objects, entries may be null
    8138     * @return the initial sequence of characters that are common to all Strings
    8139     * in the array; empty String if the array is null, the elements are all null
    8140     * or if there is no common prefix.
    8141     * @since 2.4
    8142     */
    8143    public static String getCommonPrefix(final String... strs) {
    8144        if (strs == null || strs.length == 0) {
    8145            return EMPTY;
    8146        }
    8147        final int smallestIndexOfDiff = indexOfDifference(strs);
    8148        if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    8149            // all strings were identical
    8150            if (strs[0] == null) {
    8151                return EMPTY;
    8152            }
    8153            return strs[0];
    8154        } else if (smallestIndexOfDiff == 0) {
    8155            // there were no common initial characters
    8156            return EMPTY;
    8157        } else {
    8158            // we found a common initial character sequence
    8159            return strs[0].substring(0, smallestIndexOfDiff);
    8160        }
    8161    }
    8162
    8163    // Misc
    8164    //-----------------------------------------------------------------------
    8165    /**
    8166     * <p>Find the Levenshtein distance between two Strings.</p>
    8167     *
    8168     * <p>This is the number of changes needed to change one String into
    8169     * another, where each change is a single character modification (deletion,
    8170     * insertion or substitution).</p>
    8171     *
    8172     * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
    8173     * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
    8174     * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
    8175     *
    8176     * <pre>
    8177     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    8178     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    8179     * StringUtils.getLevenshteinDistance("","")               = 0
    8180     * StringUtils.getLevenshteinDistance("","a")              = 1
    8181     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    8182     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    8183     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    8184     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    8185     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    8186     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    8187     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    8188     * </pre>
    8189     *
    8190     * @param s  the first String, must not be null
    8191     * @param t  the second String, must not be null
    8192     * @return result distance
    8193     * @throws IllegalArgumentException if either String input {@code null}
    8194     * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
    8195     * getLevenshteinDistance(CharSequence, CharSequence)
    8196     * @deprecated as of 3.6, use commons-text
    8197     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    8198     * LevenshteinDistance</a> instead
    8199     */
    8200    @Deprecated
    8201    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    8202        if (s == null || t == null) {
    8203            throw new IllegalArgumentException("Strings must not be null");
    8204        }
    8205
    8206        int n = s.length();
    8207        int m = t.length();
    8208
    8209        if (n == 0) {
    8210            return m;
    8211        } else if (m == 0) {
    8212            return n;
    8213        }
    8214
    8215        if (n > m) {
    8216            // swap the input strings to consume less memory
    8217            final CharSequence tmp = s;
    8218            s = t;
    8219            t = tmp;
    8220            n = m;
    8221            m = t.length();
    8222        }
    8223
    8224        final int p[] = new int[n + 1];
    8225        // indexes into strings s and t
    8226        int i; // iterates through s
    8227        int j; // iterates through t
    8228        int upper_left;
    8229        int upper;
    8230
    8231        char t_j; // jth character of t
    8232        int cost;
    8233
    8234        for (i = 0; i <= n; i++) {
    8235            p[i] = i;
    8236        }
    8237
    8238        for (j = 1; j <= m; j++) {
    8239            upper_left = p[0];
    8240            t_j = t.charAt(j - 1);
    8241            p[0] = j;
    8242
    8243            for (i = 1; i <= n; i++) {
    8244                upper = p[i];
    8245                cost = s.charAt(i - 1) == t_j ? 0 : 1;
    8246                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    8247                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
    8248                upper_left = upper;
    8249            }
    8250        }
    8251
    8252        return p[n];
    8253    }
    8254
    8255    /**
    8256     * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
    8257     * threshold.</p>
    8258     *
    8259     * <p>This is the number of changes needed to change one String into
    8260     * another, where each change is a single character modification (deletion,
    8261     * insertion or substitution).</p>
    8262     *
    8263     * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
    8264     * and Chas Emerick's implementation of the Levenshtein distance algorithm from
    8265     * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
    8266     *
    8267     * <pre>
    8268     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
    8269     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
    8270     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
    8271     * StringUtils.getLevenshteinDistance("","", 0)               = 0
    8272     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
    8273     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
    8274     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
    8275     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
    8276     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
    8277     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
    8278     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
    8279     * </pre>
    8280     *
    8281     * @param s  the first String, must not be null
    8282     * @param t  the second String, must not be null
    8283     * @param threshold the target threshold, must not be negative
    8284     * @return result distance, or {@code -1} if the distance would be greater than the threshold
    8285     * @throws IllegalArgumentException if either String input {@code null} or negative threshold
    8286     * @deprecated as of 3.6, use commons-text
    8287     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
    8288     * LevenshteinDistance</a> instead
    8289     */
    8290    @Deprecated
    8291    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
    8292        if (s == null || t == null) {
    8293            throw new IllegalArgumentException("Strings must not be null");
    8294        }
    8295        if (threshold < 0) {
    8296            throw new IllegalArgumentException("Threshold must not be negative");
    8297        }
    8298
    8299        /*
    8300        This implementation only computes the distance if it's less than or equal to the
    8301        threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    8302        distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    8303        computing a diagonal stripe of width 2k + 1 of the cost table.
    8304        It is also possible to use this to compute the unbounded Levenshtein distance by starting
    8305        the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    8306        d is the distance.
    8307
    8308        One subtlety comes from needing to ignore entries on the border of our stripe
    8309        eg.
    8310        p[] = |#|#|#|*
    8311        d[] =  *|#|#|#|
    8312        We must ignore the entry to the left of the leftmost member
    8313        We must ignore the entry above the rightmost member
    8314
    8315        Another subtlety comes from our stripe running off the matrix if the strings aren't
    8316        of the same size.  Since string s is always swapped to be the shorter of the two,
    8317        the stripe will always run off to the upper right instead of the lower left of the matrix.
    8318
    8319        As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    8320        In this case we're going to walk a stripe of length 3.  The matrix would look like so:
    8321
    8322           1 2 3 4 5
    8323        1 |#|#| | | |
    8324        2 |#|#|#| | |
    8325        3 | |#|#|#| |
    8326        4 | | |#|#|#|
    8327        5 | | | |#|#|
    8328        6 | | | | |#|
    8329        7 | | | | | |
    8330
    8331        Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    8332        into one of length 7 in edit distance of 1.
    8333
    8334        Additionally, this implementation decreases memory usage by using two
    8335        single-dimensional arrays and swapping them back and forth instead of allocating
    8336        an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    8337        when it's detected that the stripe has run off the matrix and initially filling the arrays with
    8338        large values so that entries we don't compute are ignored.
    8339
    8340        See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
    8341         */
    8342
    8343        int n = s.length(); // length of s
    8344        int m = t.length(); // length of t
    8345
    8346        // if one string is empty, the edit distance is necessarily the length of the other
    8347        if (n == 0) {
    8348            return m <= threshold ? m : -1;
    8349        } else if (m == 0) {
    8350            return n <= threshold ? n : -1;
    8351        } else if (Math.abs(n - m) > threshold) {
    8352            // no need to calculate the distance if the length difference is greater than the threshold
    8353            return -1;
    8354        }
    8355
    8356        if (n > m) {
    8357            // swap the two strings to consume less memory
    8358            final CharSequence tmp = s;
    8359            s = t;
    8360            t = tmp;
    8361            n = m;
    8362            m = t.length();
    8363        }
    8364
    8365        int p[] = new int[n + 1]; // 'previous' cost array, horizontally
    8366        int d[] = new int[n + 1]; // cost array, horizontally
    8367        int _d[]; // placeholder to assist in swapping p and d
    8368
    8369        // fill in starting table values
    8370        final int boundary = Math.min(n, threshold) + 1;
    8371        for (int i = 0; i < boundary; i++) {
    8372            p[i] = i;
    8373        }
    8374        // these fills ensure that the value above the rightmost entry of our
    8375        // stripe will be ignored in following loop iterations
    8376        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    8377        Arrays.fill(d, Integer.MAX_VALUE);
    8378
    8379        // iterates through t
    8380        for (int j = 1; j <= m; j++) {
    8381            final char t_j = t.charAt(j - 1); // jth character of t
    8382            d[0] = j;
    8383
    8384            // compute stripe indices, constrain to array size
    8385            final int min = Math.max(1, j - threshold);
    8386            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
    8387
    8388            // the stripe may lead off of the table if s and t are of different sizes
    8389            if (min > max) {
    8390                return -1;
    8391            }
    8392
    8393            // ignore entry left of leftmost
    8394            if (min > 1) {
    8395                d[min - 1] = Integer.MAX_VALUE;
    8396            }
    8397
    8398            // iterates through [min, max] in s
    8399            for (int i = min; i <= max; i++) {
    8400                if (s.charAt(i - 1) == t_j) {
    8401                    // diagonally left and up
    8402                    d[i] = p[i - 1];
    8403                } else {
    8404                    // 1 + minimum of cell to the left, to the top, diagonally left and up
    8405                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
    8406                }
    8407            }
    8408
    8409            // copy current distance counts to 'previous row' distance counts
    8410            _d = p;
    8411            p = d;
    8412            d = _d;
    8413        }
    8414
    8415        // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    8416        // distance
    8417        if (p[n] <= threshold) {
    8418            return p[n];
    8419        }
    8420        return -1;
    8421    }
    8422
    8423    /**
    8424     * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
    8425     *
    8426     * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
    8427     * Winkler increased this measure for matching initial characters.</p>
    8428     *
    8429     * <p>This implementation is based on the Jaro Winkler similarity algorithm
    8430     * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
    8431     *
    8432     * <pre>
    8433     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
    8434     * StringUtils.getJaroWinklerDistance("","")               = 0.0
    8435     * StringUtils.getJaroWinklerDistance("","a")              = 0.0
    8436     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
    8437     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
    8438     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
    8439     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
    8440     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
    8441     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
    8442     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
    8443     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
    8444     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
    8445     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
    8446     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
    8447     * </pre>
    8448     *
    8449     * @param first the first String, must not be null
    8450     * @param second the second String, must not be null
    8451     * @return result distance
    8452     * @throws IllegalArgumentException if either String input {@code null}
    8453     * @since 3.3
    8454     * @deprecated as of 3.6, use commons-text
    8455     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
    8456     * JaroWinklerDistance</a> instead
    8457     */
    8458    @Deprecated
    8459    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
    8460        final double DEFAULT_SCALING_FACTOR = 0.1;
    8461
    8462        if (first == null || second == null) {
    8463            throw new IllegalArgumentException("Strings must not be null");
    8464        }
    8465
    8466        final int[] mtp = matches(first, second);
    8467        final double m = mtp[0];
    8468        if (m == 0) {
    8469            return 0D;
    8470        }
    8471        final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
    8472        final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
    8473        return Math.round(jw * 100.0D) / 100.0D;
    8474    }
    8475
    8476    private static int[] matches(final CharSequence first, final CharSequence second) {
    8477        CharSequence max, min;
    8478        if (first.length() > second.length()) {
    8479            max = first;
    8480            min = second;
    8481        } else {
    8482            max = second;
    8483            min = first;
    8484        }
    8485        final int range = Math.max(max.length() / 2 - 1, 0);
    8486        final int[] matchIndexes = new int[min.length()];
    8487        Arrays.fill(matchIndexes, -1);
    8488        final boolean[] matchFlags = new boolean[max.length()];
    8489        int matches = 0;
    8490        for (int mi = 0; mi < min.length(); mi++) {
    8491            final char c1 = min.charAt(mi);
    8492            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
    8493                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
    8494                    matchIndexes[mi] = xi;
    8495                    matchFlags[xi] = true;
    8496                    matches++;
    8497                    break;
    8498                }
    8499            }
    8500        }
    8501        final char[] ms1 = new char[matches];
    8502        final char[] ms2 = new char[matches];
    8503        for (int i = 0, si = 0; i < min.length(); i++) {
    8504            if (matchIndexes[i] != -1) {
    8505                ms1[si] = min.charAt(i);
    8506                si++;
    8507            }
    8508        }
    8509        for (int i = 0, si = 0; i < max.length(); i++) {
    8510            if (matchFlags[i]) {
    8511                ms2[si] = max.charAt(i);
    8512                si++;
    8513            }
    8514        }
    8515        int transpositions = 0;
    8516        for (int mi = 0; mi < ms1.length; mi++) {
    8517            if (ms1[mi] != ms2[mi]) {
    8518                transpositions++;
    8519            }
    8520        }
    8521        int prefix = 0;
    8522        for (int mi = 0; mi < min.length(); mi++) {
    8523            if (first.charAt(mi) == second.charAt(mi)) {
    8524                prefix++;
    8525            } else {
    8526                break;
    8527            }
    8528        }
    8529        return new int[] { matches, transpositions / 2, prefix, max.length() };
    8530    }
    8531
    8532    /**
    8533     * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
    8534     *
    8535     * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
    8536     * TextMate, Atom and others. One point is given for every matched character. Subsequent
    8537     * matches yield two bonus points. A higher score indicates a higher similarity.</p>
    8538     *
    8539     * <pre>
    8540     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
    8541     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
    8542     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
    8543     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
    8544     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
    8545     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
    8546     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
    8547     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
    8548     * </pre>
    8549     *
    8550     * @param term a full term that should be matched against, must not be null
    8551     * @param query the query that will be matched against a term, must not be null
    8552     * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
    8553     *  both Strings to lower case.
    8554     * @return result score
    8555     * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
    8556     * @since 3.4
    8557     * @deprecated as of 3.6, use commons-text
    8558     * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
    8559     * FuzzyScore</a> instead
    8560     */
    8561    @Deprecated
    8562    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
    8563        if (term == null || query == null) {
    8564            throw new IllegalArgumentException("Strings must not be null");
    8565        } else if (locale == null) {
    8566            throw new IllegalArgumentException("Locale must not be null");
    8567        }
    8568
    8569        // fuzzy logic is case insensitive. We normalize the Strings to lower
    8570        // case right from the start. Turning characters to lower case
    8571        // via Character.toLowerCase(char) is unfortunately insufficient
    8572        // as it does not accept a locale.
    8573        final String termLowerCase = term.toString().toLowerCase(locale);
    8574        final String queryLowerCase = query.toString().toLowerCase(locale);
    8575
    8576        // the resulting score
    8577        int score = 0;
    8578
    8579        // the position in the term which will be scanned next for potential
    8580        // query character matches
    8581        int termIndex = 0;
    8582
    8583        // index of the previously matched character in the term
    8584        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
    8585
    8586        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
    8587            final char queryChar = queryLowerCase.charAt(queryIndex);
    8588
    8589            boolean termCharacterMatchFound = false;
    8590            for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
    8591                final char termChar = termLowerCase.charAt(termIndex);
    8592
    8593                if (queryChar == termChar) {
    8594                    // simple character matches result in one point
    8595                    score++;
    8596
    8597                    // subsequent character matches further improve
    8598                    // the score.
    8599                    if (previousMatchingCharacterIndex + 1 == termIndex) {
    8600                        score += 2;
    8601                    }
    8602
    8603                    previousMatchingCharacterIndex = termIndex;
    8604
    8605                    // we can leave the nested loop. Every character in the
    8606                    // query can match at most one character in the term.
    8607                    termCharacterMatchFound = true;
    8608                }
    8609            }
    8610        }
    8611
    8612        return score;
    8613    }
    8614
    8615    // startsWith
    8616    //-----------------------------------------------------------------------
    8617
    8618    /**
    8619     * <p>Check if a CharSequence starts with a specified prefix.</p>
    8620     *
    8621     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8622     * references are considered to be equal. The comparison is case sensitive.</p>
    8623     *
    8624     * <pre>
    8625     * StringUtils.startsWith(null, null)      = true
    8626     * StringUtils.startsWith(null, "abc")     = false
    8627     * StringUtils.startsWith("abcdef", null)  = false
    8628     * StringUtils.startsWith("abcdef", "abc") = true
    8629     * StringUtils.startsWith("ABCDEF", "abc") = false
    8630     * </pre>
    8631     *
    8632     * @see java.lang.String#startsWith(String)
    8633     * @param str  the CharSequence to check, may be null
    8634     * @param prefix the prefix to find, may be null
    8635     * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
    8636     *  both {@code null}
    8637     * @since 2.4
    8638     * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
    8639     */
    8640    public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
    8641        return startsWith(str, prefix, false);
    8642    }
    8643
    8644    /**
    8645     * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
    8646     *
    8647     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8648     * references are considered to be equal. The comparison is case insensitive.</p>
    8649     *
    8650     * <pre>
    8651     * StringUtils.startsWithIgnoreCase(null, null)      = true
    8652     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    8653     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    8654     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    8655     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    8656     * </pre>
    8657     *
    8658     * @see java.lang.String#startsWith(String)
    8659     * @param str  the CharSequence to check, may be null
    8660     * @param prefix the prefix to find, may be null
    8661     * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
    8662     *  both {@code null}
    8663     * @since 2.4
    8664     * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
    8665     */
    8666    public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
    8667        return startsWith(str, prefix, true);
    8668    }
    8669
    8670    /**
    8671     * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
    8672     *
    8673     * @see java.lang.String#startsWith(String)
    8674     * @param str  the CharSequence to check, may be null
    8675     * @param prefix the prefix to find, may be null
    8676     * @param ignoreCase indicates whether the compare should ignore case
    8677     *  (case insensitive) or not.
    8678     * @return {@code true} if the CharSequence starts with the prefix or
    8679     *  both {@code null}
    8680     */
    8681    private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
    8682        if (str == null || prefix == null) {
    8683            return str == prefix;
    8684        }
    8685        if (prefix.length() > str.length()) {
    8686            return false;
    8687        }
    8688        return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
    8689    }
    8690
    8691    /**
    8692     * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
    8693     *
    8694     * <pre>
    8695     * StringUtils.startsWithAny(null, null)      = false
    8696     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    8697     * StringUtils.startsWithAny("abcxyz", null)     = false
    8698     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
    8699     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    8700     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    8701     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
    8702     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
    8703     * </pre>
    8704     *
    8705     * @param sequence the CharSequence to check, may be null
    8706     * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
    8707     * @see StringUtils#startsWith(CharSequence, CharSequence)
    8708     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    8709     *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
    8710     * @since 2.5
    8711     * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
    8712     */
    8713    public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    8714        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    8715            return false;
    8716        }
    8717        for (final CharSequence searchString : searchStrings) {
    8718            if (startsWith(sequence, searchString)) {
    8719                return true;
    8720            }
    8721        }
    8722        return false;
    8723    }
    8724
    8725    // endsWith
    8726    //-----------------------------------------------------------------------
    8727
    8728    /**
    8729     * <p>Check if a CharSequence ends with a specified suffix.</p>
    8730     *
    8731     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8732     * references are considered to be equal. The comparison is case sensitive.</p>
    8733     *
    8734     * <pre>
    8735     * StringUtils.endsWith(null, null)      = true
    8736     * StringUtils.endsWith(null, "def")     = false
    8737     * StringUtils.endsWith("abcdef", null)  = false
    8738     * StringUtils.endsWith("abcdef", "def") = true
    8739     * StringUtils.endsWith("ABCDEF", "def") = false
    8740     * StringUtils.endsWith("ABCDEF", "cde") = false
    8741     * StringUtils.endsWith("ABCDEF", "")    = true
    8742     * </pre>
    8743     *
    8744     * @see java.lang.String#endsWith(String)
    8745     * @param str  the CharSequence to check, may be null
    8746     * @param suffix the suffix to find, may be null
    8747     * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
    8748     *  both {@code null}
    8749     * @since 2.4
    8750     * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
    8751     */
    8752    public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
    8753        return endsWith(str, suffix, false);
    8754    }
    8755
    8756    /**
    8757     * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
    8758     *
    8759     * <p>{@code null}s are handled without exceptions. Two {@code null}
    8760     * references are considered to be equal. The comparison is case insensitive.</p>
    8761     *
    8762     * <pre>
    8763     * StringUtils.endsWithIgnoreCase(null, null)      = true
    8764     * StringUtils.endsWithIgnoreCase(null, "def")     = false
    8765     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    8766     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    8767     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    8768     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    8769     * </pre>
    8770     *
    8771     * @see java.lang.String#endsWith(String)
    8772     * @param str  the CharSequence to check, may be null
    8773     * @param suffix the suffix to find, may be null
    8774     * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
    8775     *  both {@code null}
    8776     * @since 2.4
    8777     * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
    8778     */
    8779    public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
    8780        return endsWith(str, suffix, true);
    8781    }
    8782
    8783    /**
    8784     * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
    8785     *
    8786     * @see java.lang.String#endsWith(String)
    8787     * @param str  the CharSequence to check, may be null
    8788     * @param suffix the suffix to find, may be null
    8789     * @param ignoreCase indicates whether the compare should ignore case
    8790     *  (case insensitive) or not.
    8791     * @return {@code true} if the CharSequence starts with the prefix or
    8792     *  both {@code null}
    8793     */
    8794    private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
    8795        if (str == null || suffix == null) {
    8796            return str == suffix;
    8797        }
    8798        if (suffix.length() > str.length()) {
    8799            return false;
    8800        }
    8801        final int strOffset = str.length() - suffix.length();
    8802        return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
    8803    }
    8804
    8805    /**
    8806     * <p>
    8807     * Similar to <a
    8808     * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
    8809     * -space</a>
    8810     * </p>
    8811     * <p>
    8812     * The function returns the argument string with whitespace normalized by using
    8813     * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
    8814     * and then replacing sequences of whitespace characters by a single space.
    8815     * </p>
    8816     * In XML Whitespace characters are the same as those allowed by the <a
    8817     * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
    8818     * <p>
    8819     * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
    8820     *
    8821     * <p>For reference:</p>
    8822     * <ul>
    8823     * <li>\x0B = vertical tab</li>
    8824     * <li>\f = #xC = form feed</li>
    8825     * <li>#x20 = space</li>
    8826     * <li>#x9 = \t</li>
    8827     * <li>#xA = \n</li>
    8828     * <li>#xD = \r</li>
    8829     * </ul>
    8830     *
    8831     * <p>
    8832     * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
    8833     * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
    8834     * ends of this String.
    8835     * </p>
    8836     *
    8837     * @see Pattern
    8838     * @see #trim(String)
    8839     * @see <a
    8840     *      href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
    8841     * @param str the source String to normalize whitespaces from, may be null
    8842     * @return the modified string with whitespace normalized, {@code null} if null String input
    8843     *
    8844     * @since 3.0
    8845     */
    8846    public static String normalizeSpace(final String str) {
    8847        // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
    8848        // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
    8849        if (isEmpty(str)) {
    8850            return str;
    8851        }
    8852        final int size = str.length();
    8853        final char[] newChars = new char[size];
    8854        int count = 0;
    8855        int whitespacesCount = 0;
    8856        boolean startWhitespaces = true;
    8857        for (int i = 0; i < size; i++) {
    8858            final char actualChar = str.charAt(i);
    8859            final boolean isWhitespace = Character.isWhitespace(actualChar);
    8860            if (isWhitespace) {
    8861                if (whitespacesCount == 0 && !startWhitespaces) {
    8862                    newChars[count++] = SPACE.charAt(0);
    8863                }
    8864                whitespacesCount++;
    8865            } else {
    8866                startWhitespaces = false;
    8867                newChars[count++] = (actualChar == 160 ? 32 : actualChar);
    8868                whitespacesCount = 0;
    8869            }
    8870        }
    8871        if (startWhitespaces) {
    8872            return EMPTY;
    8873        }
    8874        return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
    8875    }
    8876
    8877    /**
    8878     * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
    8879     *
    8880     * <pre>
    8881     * StringUtils.endsWithAny(null, null)      = false
    8882     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
    8883     * StringUtils.endsWithAny("abcxyz", null)     = false
    8884     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
    8885     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
    8886     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    8887     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
    8888     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
    8889     * </pre>
    8890     *
    8891     * @param sequence  the CharSequence to check, may be null
    8892     * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
    8893     * @see StringUtils#endsWith(CharSequence, CharSequence)
    8894     * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
    8895     *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
    8896     * @since 3.0
    8897     */
    8898    public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
    8899        if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
    8900            return false;
    8901        }
    8902        for (final CharSequence searchString : searchStrings) {
    8903            if (endsWith(sequence, searchString)) {
    8904                return true;
    8905            }
    8906        }
    8907        return false;
    8908    }
    8909
    8910    /**
    8911     * Appends the suffix to the end of the string if the string does not
    8912     * already end with the suffix.
    8913     *
    8914     * @param str The string.
    8915     * @param suffix The suffix to append to the end of the string.
    8916     * @param ignoreCase Indicates whether the compare should ignore case.
    8917     * @param suffixes Additional suffixes that are valid terminators (optional).
    8918     *
    8919     * @return A new String if suffix was appended, the same string otherwise.
    8920     */
    8921    private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
    8922        if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
    8923            return str;
    8924        }
    8925        if (suffixes != null && suffixes.length > 0) {
    8926            for (final CharSequence s : suffixes) {
    8927                if (endsWith(str, s, ignoreCase)) {
    8928                    return str;
    8929                }
    8930            }
    8931        }
    8932        return str + suffix.toString();
    8933    }
    8934
    8935    /**
    8936     * Appends the suffix to the end of the string if the string does not
    8937     * already end with any of the suffixes.
    8938     *
    8939     * <pre>
    8940     * StringUtils.appendIfMissing(null, null) = null
    8941     * StringUtils.appendIfMissing("abc", null) = "abc"
    8942     * StringUtils.appendIfMissing("", "xyz") = "xyz"
    8943     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
    8944     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
    8945     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
    8946     * </pre>
    8947     * <p>With additional suffixes,</p>
    8948     * <pre>
    8949     * StringUtils.appendIfMissing(null, null, null) = null
    8950     * StringUtils.appendIfMissing("abc", null, null) = "abc"
    8951     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
    8952     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    8953     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
    8954     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
    8955     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
    8956     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
    8957     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
    8958     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
    8959     * </pre>
    8960     *
    8961     * @param str The string.
    8962     * @param suffix The suffix to append to the end of the string.
    8963     * @param suffixes Additional suffixes that are valid terminators.
    8964     *
    8965     * @return A new String if suffix was appended, the same string otherwise.
    8966     *
    8967     * @since 3.2
    8968     */
    8969    public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    8970        return appendIfMissing(str, suffix, false, suffixes);
    8971    }
    8972
    8973    /**
    8974     * Appends the suffix to the end of the string if the string does not
    8975     * already end, case insensitive, with any of the suffixes.
    8976     *
    8977     * <pre>
    8978     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
    8979     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
    8980     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
    8981     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
    8982     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
    8983     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
    8984     * </pre>
    8985     * <p>With additional suffixes,</p>
    8986     * <pre>
    8987     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
    8988     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
    8989     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
    8990     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
    8991     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    8992     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
    8993     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
    8994     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
    8995     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
    8996     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
    8997     * </pre>
    8998     *
    8999     * @param str The string.
    9000     * @param suffix The suffix to append to the end of the string.
    9001     * @param suffixes Additional suffixes that are valid terminators.
    9002     *
    9003     * @return A new String if suffix was appended, the same string otherwise.
    9004     *
    9005     * @since 3.2
    9006     */
    9007    public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
    9008        return appendIfMissing(str, suffix, true, suffixes);
    9009    }
    9010
    9011    /**
    9012     * Prepends the prefix to the start of the string if the string does not
    9013     * already start with any of the prefixes.
    9014     *
    9015     * @param str The string.
    9016     * @param prefix The prefix to prepend to the start of the string.
    9017     * @param ignoreCase Indicates whether the compare should ignore case.
    9018     * @param prefixes Additional prefixes that are valid (optional).
    9019     *
    9020     * @return A new String if prefix was prepended, the same string otherwise.
    9021     */
    9022    private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
    9023        if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
    9024            return str;
    9025        }
    9026        if (prefixes != null && prefixes.length > 0) {
    9027            for (final CharSequence p : prefixes) {
    9028                if (startsWith(str, p, ignoreCase)) {
    9029                    return str;
    9030                }
    9031            }
    9032        }
    9033        return prefix.toString() + str;
    9034    }
    9035
    9036    /**
    9037     * Prepends the prefix to the start of the string if the string does not
    9038     * already start with any of the prefixes.
    9039     *
    9040     * <pre>
    9041     * StringUtils.prependIfMissing(null, null) = null
    9042     * StringUtils.prependIfMissing("abc", null) = "abc"
    9043     * StringUtils.prependIfMissing("", "xyz") = "xyz"
    9044     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
    9045     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
    9046     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
    9047     * </pre>
    9048     * <p>With additional prefixes,</p>
    9049     * <pre>
    9050     * StringUtils.prependIfMissing(null, null, null) = null
    9051     * StringUtils.prependIfMissing("abc", null, null) = "abc"
    9052     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
    9053     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    9054     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
    9055     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
    9056     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
    9057     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
    9058     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
    9059     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
    9060     * </pre>
    9061     *
    9062     * @param str The string.
    9063     * @param prefix The prefix to prepend to the start of the string.
    9064     * @param prefixes Additional prefixes that are valid.
    9065     *
    9066     * @return A new String if prefix was prepended, the same string otherwise.
    9067     *
    9068     * @since 3.2
    9069     */
    9070    public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    9071        return prependIfMissing(str, prefix, false, prefixes);
    9072    }
    9073
    9074    /**
    9075     * Prepends the prefix to the start of the string if the string does not
    9076     * already start, case insensitive, with any of the prefixes.
    9077     *
    9078     * <pre>
    9079     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
    9080     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
    9081     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
    9082     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
    9083     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
    9084     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
    9085     * </pre>
    9086     * <p>With additional prefixes,</p>
    9087     * <pre>
    9088     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
    9089     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
    9090     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
    9091     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
    9092     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
    9093     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
    9094     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
    9095     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
    9096     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
    9097     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
    9098     * </pre>
    9099     *
    9100     * @param str The string.
    9101     * @param prefix The prefix to prepend to the start of the string.
    9102     * @param prefixes Additional prefixes that are valid (optional).
    9103     *
    9104     * @return A new String if prefix was prepended, the same string otherwise.
    9105     *
    9106     * @since 3.2
    9107     */
    9108    public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
    9109        return prependIfMissing(str, prefix, true, prefixes);
    9110    }
    9111
    9112    /**
    9113     * Converts a <code>byte[]</code> to a String using the specified character encoding.
    9114     *
    9115     * @param bytes
    9116     *            the byte array to read from
    9117     * @param charsetName
    9118     *            the encoding to use, if null then use the platform default
    9119     * @return a new String
    9120     * @throws UnsupportedEncodingException
    9121     *             If the named charset is not supported
    9122     * @throws NullPointerException
    9123     *             if the input is null
    9124     * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
    9125     * @since 3.1
    9126     */
    9127    @Deprecated
    9128    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
    9129        return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
    9130    }
    9131
    9132    /**
    9133     * Converts a <code>byte[]</code> to a String using the specified character encoding.
    9134     *
    9135     * @param bytes
    9136     *            the byte array to read from
    9137     * @param charset
    9138     *            the encoding to use, if null then use the platform default
    9139     * @return a new String
    9140     * @throws NullPointerException
    9141     *             if {@code bytes} is null
    9142     * @since 3.2
    9143     * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
    9144     */
    9145    public static String toEncodedString(final byte[] bytes, final Charset charset) {
    9146        return new String(bytes, charset != null ? charset : Charset.defaultCharset());
    9147    }
    9148
    9149    /**
    9150     * <p>
    9151     * Wraps a string with a char.
    9152     * </p>
    9153     *
    9154     * <pre>
    9155     * StringUtils.wrap(null, *)        = null
    9156     * StringUtils.wrap("", *)          = ""
    9157     * StringUtils.wrap("ab", '\0')     = "ab"
    9158     * StringUtils.wrap("ab", 'x')      = "xabx"
    9159     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9160     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
    9161     * </pre>
    9162     *
    9163     * @param str
    9164     *            the string to be wrapped, may be {@code null}
    9165     * @param wrapWith
    9166     *            the char that will wrap {@code str}
    9167     * @return the wrapped string, or {@code null} if {@code str==null}
    9168     * @since 3.4
    9169     */
    9170    public static String wrap(final String str, final char wrapWith) {
    9171
    9172        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9173            return str;
    9174        }
    9175
    9176        return wrapWith + str + wrapWith;
    9177    }
    9178
    9179    /**
    9180     * <p>
    9181     * Wraps a String with another String.
    9182     * </p>
    9183     *
    9184     * <p>
    9185     * A {@code null} input String returns {@code null}.
    9186     * </p>
    9187     *
    9188     * <pre>
    9189     * StringUtils.wrap(null, *)         = null
    9190     * StringUtils.wrap("", *)           = ""
    9191     * StringUtils.wrap("ab", null)      = "ab"
    9192     * StringUtils.wrap("ab", "x")       = "xabx"
    9193     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9194     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
    9195     * StringUtils.wrap("ab", "'")       = "'ab'"
    9196     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
    9197     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9198     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9199     * </pre>
    9200     *
    9201     * @param str
    9202     *            the String to be wrapper, may be null
    9203     * @param wrapWith
    9204     *            the String that will wrap str
    9205     * @return wrapped String, {@code null} if null String input
    9206     * @since 3.4
    9207     */
    9208    public static String wrap(final String str, final String wrapWith) {
    9209
    9210        if (isEmpty(str) || isEmpty(wrapWith)) {
    9211            return str;
    9212        }
    9213
    9214        return wrapWith.concat(str).concat(wrapWith);
    9215    }
    9216
    9217    /**
    9218     * <p>
    9219     * Wraps a string with a char if that char is missing from the start or end of the given string.
    9220     * </p>
    9221     *
    9222     * <pre>
    9223     * StringUtils.wrap(null, *)        = null
    9224     * StringUtils.wrap("", *)          = ""
    9225     * StringUtils.wrap("ab", '\0')     = "ab"
    9226     * StringUtils.wrap("ab", 'x')      = "xabx"
    9227     * StringUtils.wrap("ab", '\'')     = "'ab'"
    9228     * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
    9229     * StringUtils.wrap("/", '/')  = "/"
    9230     * StringUtils.wrap("a/b/c", '/')  = "/a/b/c/"
    9231     * StringUtils.wrap("/a/b/c", '/')  = "/a/b/c/"
    9232     * StringUtils.wrap("a/b/c/", '/')  = "/a/b/c/"
    9233     * </pre>
    9234     *
    9235     * @param str
    9236     *            the string to be wrapped, may be {@code null}
    9237     * @param wrapWith
    9238     *            the char that will wrap {@code str}
    9239     * @return the wrapped string, or {@code null} if {@code str==null}
    9240     * @since 3.5
    9241     */
    9242    public static String wrapIfMissing(final String str, final char wrapWith) {
    9243        if (isEmpty(str) || wrapWith == CharUtils.NUL) {
    9244            return str;
    9245        }
    9246        final StringBuilder builder = new StringBuilder(str.length() + 2);
    9247        if (str.charAt(0) != wrapWith) {
    9248            builder.append(wrapWith);
    9249        }
    9250        builder.append(str);
    9251        if (str.charAt(str.length() - 1) != wrapWith) {
    9252            builder.append(wrapWith);
    9253        }
    9254        return builder.toString();
    9255    }
    9256
    9257    /**
    9258     * <p>
    9259     * Wraps a string with a string if that string is missing from the start or end of the given string.
    9260     * </p>
    9261     *
    9262     * <pre>
    9263     * StringUtils.wrap(null, *)         = null
    9264     * StringUtils.wrap("", *)           = ""
    9265     * StringUtils.wrap("ab", null)      = "ab"
    9266     * StringUtils.wrap("ab", "x")       = "xabx"
    9267     * StringUtils.wrap("ab", "\"")      = "\"ab\""
    9268     * StringUtils.wrap("\"ab\"", "\"")  = "\"ab\""
    9269     * StringUtils.wrap("ab", "'")       = "'ab'"
    9270     * StringUtils.wrap("'abcd'", "'")   = "'abcd'"
    9271     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
    9272     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
    9273     * StringUtils.wrap("/", "/")  = "/"
    9274     * StringUtils.wrap("a/b/c", "/")  = "/a/b/c/"
    9275     * StringUtils.wrap("/a/b/c", "/")  = "/a/b/c/"
    9276     * StringUtils.wrap("a/b/c/", "/")  = "/a/b/c/"
    9277     * </pre>
    9278     *
    9279     * @param str
    9280     *            the string to be wrapped, may be {@code null}
    9281     * @param wrapWith
    9282     *            the char that will wrap {@code str}
    9283     * @return the wrapped string, or {@code null} if {@code str==null}
    9284     * @since 3.5
    9285     */
    9286    public static String wrapIfMissing(final String str, final String wrapWith) {
    9287        if (isEmpty(str) || isEmpty(wrapWith)) {
    9288            return str;
    9289        }
    9290        final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
    9291        if (!str.startsWith(wrapWith)) {
    9292            builder.append(wrapWith);
    9293        }
    9294        builder.append(str);
    9295        if (!str.endsWith(wrapWith)) {
    9296            builder.append(wrapWith);
    9297        }
    9298        return builder.toString();
    9299    }
    9300
    9301    /**
    9302     * <p>
    9303     * Unwraps a given string from anther string.
    9304     * </p>
    9305     *
    9306     * <pre>
    9307     * StringUtils.unwrap(null, null)         = null
    9308     * StringUtils.unwrap(null, "")           = null
    9309     * StringUtils.unwrap(null, "1")          = null
    9310     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
    9311     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
    9312     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
    9313     * StringUtils.unwrap("A", "#")           = "A"
    9314     * StringUtils.unwrap("#A", "#")          = "#A"
    9315     * StringUtils.unwrap("A#", "#")          = "A#"
    9316     * </pre>
    9317     *
    9318     * @param str
    9319     *          the String to be unwrapped, can be null
    9320     * @param wrapToken
    9321     *          the String used to unwrap
    9322     * @return unwrapped String or the original string
    9323     *          if it is not quoted properly with the wrapToken
    9324     * @since 3.6
    9325     */
    9326    public static String unwrap(final String str, final String wrapToken) {
    9327        if (isEmpty(str) || isEmpty(wrapToken)) {
    9328            return str;
    9329        }
    9330
    9331        if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
    9332            final int startIndex = str.indexOf(wrapToken);
    9333            final int endIndex = str.lastIndexOf(wrapToken);
    9334            final int wrapLength = wrapToken.length();
    9335            if (startIndex != -1 && endIndex != -1) {
    9336                return str.substring(startIndex + wrapLength, endIndex);
    9337            }
    9338        }
    9339
    9340        return str;
    9341    }
    9342
    9343    /**
    9344     * <p>
    9345     * Unwraps a given string from a character.
    9346     * </p>
    9347     *
    9348     * <pre>
    9349     * StringUtils.unwrap(null, null)         = null
    9350     * StringUtils.unwrap(null, '\0')         = null
    9351     * StringUtils.unwrap(null, '1')          = null
    9352     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
    9353     * StringUtils.unwrap("AABabcBAA", 'A')  = "ABabcBA"
    9354     * StringUtils.unwrap("A", '#')           = "A"
    9355     * StringUtils.unwrap("#A", '#')          = "#A"
    9356     * StringUtils.unwrap("A#", '#')          = "A#"
    9357     * </pre>
    9358     *
    9359     * @param str
    9360     *          the String to be unwrapped, can be null
    9361     * @param wrapChar
    9362     *          the character used to unwrap
    9363     * @return unwrapped String or the original string
    9364     *          if it is not quoted properly with the wrapChar
    9365     * @since 3.6
    9366     */
    9367    public static String unwrap(final String str, final char wrapChar) {
    9368        if (isEmpty(str) || wrapChar == CharUtils.NUL) {
    9369            return str;
    9370        }
    9371
    9372        if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
    9373            final int startIndex = 0;
    9374            final int endIndex = str.length() - 1;
    9375            if (endIndex != -1) {
    9376                return str.substring(startIndex + 1, endIndex);
    9377            }
    9378        }
    9379
    9380        return str;
    9381    }
    9382
    9383    /**
    9384     * <p>Converts a {@code CharSequence} into an array of code points.</p>
    9385     *
    9386     * <p>Valid pairs of surrogate code units will be converted into a single supplementary
    9387     * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
    9388     * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
    9389     *
    9390     * <pre>
    9391     * StringUtils.toCodePoints(null)   =  null
    9392     * StringUtils.toCodePoints("")     =  []  // empty array
    9393     * </pre>
    9394     *
    9395     * @param str the character sequence to convert
    9396     * @return an array of code points
    9397     * @since 3.6
    9398     */
    9399    public static int[] toCodePoints(final CharSequence str) {
    9400        if (str == null) {
    9401            return null;
    9402        }
    9403        if (str.length() == 0) {
    9404            return ArrayUtils.EMPTY_INT_ARRAY;
    9405        }
    9406
    9407        final String s = str.toString();
    9408        final int[] result = new int[s.codePointCount(0, s.length())];
    9409        int index = 0;
    9410        for (int i = 0; i < result.length; i++) {
    9411            result[i] = s.codePointAt(index);
    9412            index += Character.charCount(result[i]);
    9413        }
    9414        return result;
    9415    }
    9416}