    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     */
    017    package org.apache.commons.lang3;
    018
    019    import java.util.ArrayList;
    020    import java.util.Iterator;
    021    import java.util.List;
    022    import java.util.Locale;
    023
    024    /**
    025     * <p>Operations on {@link java.lang.String} that are
    026     * <code>null</code> safe.</p>
    027     *
    028     * <ul>
    029     *  <li><b>IsEmpty/IsBlank</b>
    030     *      - checks if a String contains text</li>
    031     *  <li><b>Trim/Strip</b>
    032     *      - removes leading and trailing whitespace</li>
    033     *  <li><b>Equals</b>
    034     *      - compares two strings null-safe</li>
    035     *  <li><b>startsWith</b>
    036     *      - check if a String starts with a prefix null-safe</li>
    037     *  <li><b>endsWith</b>
    038     *      - check if a String ends with a suffix null-safe</li>
    039     *  <li><b>IndexOf/LastIndexOf/Contains</b>
    040     *      - null-safe index-of checks
    041     *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
    042     *      - index-of any of a set of Strings</li>
    043     *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
    044     *      - does String contains only/none/any of these characters</li>
    045     *  <li><b>Substring/Left/Right/Mid</b>
    046     *      - null-safe substring extractions</li>
    047     *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
    048     *      - substring extraction relative to other strings</li>
    049     *  <li><b>Split/Join</b>
    050     *      - splits a String into an array of substrings and vice versa</li>
    051     *  <li><b>Remove/Delete</b>
    052     *      - removes part of a String</li>
    053     *  <li><b>Replace/Overlay</b>
    054     *      - Searches a String and replaces one String with another</li>
    055     *  <li><b>Chomp/Chop</b>
    056     *      - removes the last part of a String</li>
    057     *  <li><b>LeftPad/RightPad/Center/Repeat</b>
    058     *      - pads a String</li>
    059     *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
    060     *      - changes the case of a String</li>
    061     *  <li><b>CountMatches</b>
    062     *      - counts the number of occurrences of one String in another</li>
    063     *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
    064     *      - checks the characters in a String</li>
    065     *  <li><b>DefaultString</b>
    066     *      - protects against a null input String</li>
    067     *  <li><b>Reverse/ReverseDelimited</b>
    068     *      - reverses a String</li>
    069     *  <li><b>Abbreviate</b>
    070     *      - abbreviates a string using ellipsis</li>
    071     *  <li><b>Difference</b>
    072     *      - compares Strings and reports on their differences</li>
    073     *  <li><b>LevensteinDistance</b>
    074     *      - the number of changes needed to change one String into another</li>
    075     * </ul>
    076     *
    077     * <p>The <code>StringUtils</code> class defines certain words related to
    078     * String handling.</p>
    079     *
    080     * <ul>
    081     *  <li>null - <code>null</code></li>
    082     *  <li>empty - a zero-length string (<code>""</code>)</li>
    083     *  <li>space - the space character (<code>' '</code>, char 32)</li>
    084     *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
    085     *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
    086     * </ul>
    087     *
    088     * <p><code>StringUtils</code> handles <code>null</code> input Strings quietly.
    089     * That is to say that a <code>null</code> input will return <code>null</code>.
    090     * Where a <code>boolean</code> or <code>int</code> is being returned
    091     * details vary by method.</p>
    092     *
    093     * <p>A side effect of the <code>null</code> handling is that a
    094     * <code>NullPointerException</code> should be considered a bug in
    095     * <code>StringUtils</code>.</p>
    096     *
    097     * <p>Methods in this class give sample code to explain their operation.
    098     * The symbol <code>*</code> is used to indicate any input including <code>null</code>.</p>
    099     *
    100     * <p>#ThreadSafe#</p>
    101     * @see java.lang.String
    102     * @author Apache Software Foundation
    103     * @author <a href="http://jakarta.apache.org/turbine/">Apache Jakarta Turbine</a>
    104     * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
    105     * @author Daniel L. Rall
    106     * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
    107     * @author <a href="mailto:ed@apache.org">Ed Korthof</a>
    108     * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a>
    109     * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a>
    110     * @author Holger Krauth
    111     * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
    112     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    113     * @author Arun Mammen Thomas
    114     * @author Gary Gregory
    115     * @author Phil Steitz
    116     * @author Al Chou
    117     * @author Michael Davey
    118     * @author Reuben Sivan
    119     * @author Chris Hyzer
    120     * @author Scott Johnson
    121     * @since 1.0
    122     * @version $Id: StringUtils.java 965937 2010-07-20 18:03:47Z bayard $
    123     */
    124    //@Immutable
    125    public class StringUtils {
    126        // Performance testing notes (JDK 1.4, Jul03, scolebourne)
    127        // Whitespace:
    128        // Character.isWhitespace() is faster than WHITESPACE.indexOf()
    129        // where WHITESPACE is a string of all whitespace characters
    130        //
    131        // Character access:
    132        // String.charAt(n) versus toCharArray(), then array[n]
    133        // String.charAt(n) is about 15% worse for a 10K string
    134        // They are about equal for a length 50 string
    135        // String.charAt(n) is about 4 times better for a length 3 string
    136        // String.charAt(n) is best bet overall
    137        //
    138        // Append:
    139        // String.concat about twice as fast as StringBuffer.append
    140        // (not sure who tested this)
    141
    142        /**
    143         * The empty String <code>""</code>.
    144         * @since 2.0
    145         */
    146        public static final String EMPTY = "";
    147
    148        /**
    149         * Represents a failed index search.
    150         * @since 2.1
    151         */
    152        public static final int INDEX_NOT_FOUND = -1;
    153
    154        /**
    155         * <p>The maximum size to which the padding constant(s) can expand.</p>
    156         */
    157        private static final int PAD_LIMIT = 8192;
    158
    159        /**
    160         * <p><code>StringUtils</code> instances should NOT be constructed in
    161         * standard programming. Instead, the class should be used as
    162         * <code>StringUtils.trim(" foo ");</code>.</p>
    163         *
    164         * <p>This constructor is public to permit tools that require a JavaBean
    165         * instance to operate.</p>
    166         */
    167        public StringUtils() {
    168            super();
    169        }
    170
    171        // Empty checks
    172        //-----------------------------------------------------------------------
    173        /**
    174         * <p>Checks if a CharSequence is empty ("") or null.</p>
    175         *
    176         * <pre>
    177         * StringUtils.isEmpty(null)      = true
    178         * StringUtils.isEmpty("")        = true
    179         * StringUtils.isEmpty(" ")       = false
    180         * StringUtils.isEmpty("bob")     = false
    181         * StringUtils.isEmpty("  bob  ") = false
    182         * </pre>
    183         *
    184         * <p>NOTE: This method changed in Lang version 2.0.
    185         * It no longer trims the CharSequence.
    186         * That functionality is available in isBlank().</p>
    187         *
    188         * @param cs  the CharSequence to check, may be null
    189         * @return <code>true</code> if the CharSequence is empty or null
    190         * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
    191         */
    192        public static boolean isEmpty(CharSequence cs) {
    193            return cs == null || cs.length() == 0;
    194        }
    195
    196        /**
    197         * <p>Checks if a CharSequence is not empty ("") and not null.</p>
    198         *
    199         * <pre>
    200         * StringUtils.isNotEmpty(null)      = false
    201         * StringUtils.isNotEmpty("")        = false
    202         * StringUtils.isNotEmpty(" ")       = true
    203         * StringUtils.isNotEmpty("bob")     = true
    204         * StringUtils.isNotEmpty("  bob  ") = true
    205         * </pre>
    206         *
    207         * @param cs  the CharSequence to check, may be null
    208         * @return <code>true</code> if the CharSequence is not empty and not null
    209         * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
    210         */
    211        public static boolean isNotEmpty(CharSequence cs) {
    212            return !StringUtils.isEmpty(cs);
    213        }
    214
    215        /**
    216         * <p>Checks if a CharSequence is whitespace, empty ("") or null.</p>
    217         *
    218         * <pre>
    219         * StringUtils.isBlank(null)      = true
    220         * StringUtils.isBlank("")        = true
    221         * StringUtils.isBlank(" ")       = true
    222         * StringUtils.isBlank("bob")     = false
    223         * StringUtils.isBlank("  bob  ") = false
    224         * </pre>
    225         *
    226         * @param cs  the CharSequence to check, may be null
    227         * @return <code>true</code> if the CharSequence is null, empty or whitespace
    228         * @since 2.0
    229         * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
    230         */
    231        public static boolean isBlank(CharSequence cs) {
    232            int strLen;
    233            if (cs == null || (strLen = cs.length()) == 0) {
    234                return true;
    235            }
    236            for (int i = 0; i < strLen; i++) {
    237                if ((Character.isWhitespace(cs.charAt(i)) == false)) {
    238                    return false;
    239                }
    240            }
    241            return true;
    242        }
    243
    244        /**
    245         * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
    246         *
    247         * <pre>
    248         * StringUtils.isNotBlank(null)      = false
    249         * StringUtils.isNotBlank("")        = false
    250         * StringUtils.isNotBlank(" ")       = false
    251         * StringUtils.isNotBlank("bob")     = true
    252         * StringUtils.isNotBlank("  bob  ") = true
    253         * </pre>
    254         *
    255         * @param cs  the CharSequence to check, may be null
    256         * @return <code>true</code> if the CharSequence is
    257         *  not empty and not null and not whitespace
    258         * @since 2.0
    259         * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
    260         */
    261        public static boolean isNotBlank(CharSequence cs) {
    262            return !StringUtils.isBlank(cs);
    263        }
    264
    265        // Trim
    266        //-----------------------------------------------------------------------
    267        /**
    268         * <p>Removes control characters (char &lt;= 32) from both
    269         * ends of this String, handling <code>null</code> by returning
    270         * <code>null</code>.</p>
    271         *
    272         * <p>The String is trimmed using {@link String#trim()}.
    273         * Trim removes start and end characters &lt;= 32.
    274         * To strip whitespace use {@link #strip(String)}.</p>
    275         *
    276         * <p>To trim your choice of characters, use the
    277         * {@link #strip(String, String)} methods.</p>
    278         *
    279         * <pre>
    280         * StringUtils.trim(null)          = null
    281         * StringUtils.trim("")            = ""
    282         * StringUtils.trim("     ")       = ""
    283         * StringUtils.trim("abc")         = "abc"
    284         * StringUtils.trim("    abc    ") = "abc"
    285         * </pre>
    286         *
    287         * @param str  the String to be trimmed, may be null
    288         * @return the trimmed string, <code>null</code> if null String input
    289         */
    290        public static String trim(String str) {
    291            return str == null ? null : str.trim();
    292        }
    293
    294        /**
    295         * <p>Removes control characters (char &lt;= 32) from both
    296         * ends of this String returning <code>null</code> if the String is
    297         * empty ("") after the trim or if it is <code>null</code>.
    298         *
    299         * <p>The String is trimmed using {@link String#trim()}.
    300         * Trim removes start and end characters &lt;= 32.
    301         * To strip whitespace use {@link #stripToNull(String)}.</p>
    302         *
    303         * <pre>
    304         * StringUtils.trimToNull(null)          = null
    305         * StringUtils.trimToNull("")            = null
    306         * StringUtils.trimToNull("     ")       = null
    307         * StringUtils.trimToNull("abc")         = "abc"
    308         * StringUtils.trimToNull("    abc    ") = "abc"
    309         * </pre>
    310         *
    311         * @param str  the String to be trimmed, may be null
    312         * @return the trimmed String,
    313         *  <code>null</code> if only chars &lt;= 32, empty or null String input
    314         * @since 2.0
    315         */
    316        public static String trimToNull(String str) {
    317            String ts = trim(str);
    318            return isEmpty(ts) ? null : ts;
    319        }
    320
    321        /**
    322         * <p>Removes control characters (char &lt;= 32) from both
    323         * ends of this String returning an empty String ("") if the String
    324         * is empty ("") after the trim or if it is <code>null</code>.
    325         *
    326         * <p>The String is trimmed using {@link String#trim()}.
    327         * Trim removes start and end characters &lt;= 32.
    328         * To strip whitespace use {@link #stripToEmpty(String)}.</p>
    329         *
    330         * <pre>
    331         * StringUtils.trimToEmpty(null)          = ""
    332         * StringUtils.trimToEmpty("")            = ""
    333         * StringUtils.trimToEmpty("     ")       = ""
    334         * StringUtils.trimToEmpty("abc")         = "abc"
    335         * StringUtils.trimToEmpty("    abc    ") = "abc"
    336         * </pre>
    337         *
    338         * @param str  the String to be trimmed, may be null
    339         * @return the trimmed String, or an empty String if <code>null</code> input
    340         * @since 2.0
    341         */
    342        public static String trimToEmpty(String str) {
    343            return str == null ? EMPTY : str.trim();
    344        }
    345
    346        // Stripping
    347        //-----------------------------------------------------------------------
    348        /**
    349         * <p>Strips whitespace from the start and end of a String.</p>
    350         *
    351         * <p>This is similar to {@link #trim(String)} but removes whitespace.
    352         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    353         *
    354         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    355         *
    356         * <pre>
    357         * StringUtils.strip(null)     = null
    358         * StringUtils.strip("")       = ""
    359         * StringUtils.strip("   ")    = ""
    360         * StringUtils.strip("abc")    = "abc"
    361         * StringUtils.strip("  abc")  = "abc"
    362         * StringUtils.strip("abc  ")  = "abc"
    363         * StringUtils.strip(" abc ")  = "abc"
    364         * StringUtils.strip(" ab c ") = "ab c"
    365         * </pre>
    366         *
    367         * @param str  the String to remove whitespace from, may be null
    368         * @return the stripped String, <code>null</code> if null String input
    369         */
    370        public static String strip(String str) {
    371            return strip(str, null);
    372        }
    373
    374        /**
    375         * <p>Strips whitespace from the start and end of a String  returning
    376         * <code>null</code> if the String is empty ("") after the strip.</p>
    377         *
    378         * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
    379         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    380         *
    381         * <pre>
    382         * StringUtils.stripToNull(null)     = null
    383         * StringUtils.stripToNull("")       = null
    384         * StringUtils.stripToNull("   ")    = null
    385         * StringUtils.stripToNull("abc")    = "abc"
    386         * StringUtils.stripToNull("  abc")  = "abc"
    387         * StringUtils.stripToNull("abc  ")  = "abc"
    388         * StringUtils.stripToNull(" abc ")  = "abc"
    389         * StringUtils.stripToNull(" ab c ") = "ab c"
    390         * </pre>
    391         *
    392         * @param str  the String to be stripped, may be null
    393         * @return the stripped String,
    394         *  <code>null</code> if whitespace, empty or null String input
    395         * @since 2.0
    396         */
    397        public static String stripToNull(String str) {
    398            if (str == null) {
    399                return null;
    400            }
    401            str = strip(str, null);
    402            return str.length() == 0 ? null : str;
    403        }
    404
    405        /**
    406         * <p>Strips whitespace from the start and end of a String  returning
    407         * an empty String if <code>null</code> input.</p>
    408         *
    409         * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
    410         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    411         *
    412         * <pre>
    413         * StringUtils.stripToEmpty(null)     = ""
    414         * StringUtils.stripToEmpty("")       = ""
    415         * StringUtils.stripToEmpty("   ")    = ""
    416         * StringUtils.stripToEmpty("abc")    = "abc"
    417         * StringUtils.stripToEmpty("  abc")  = "abc"
    418         * StringUtils.stripToEmpty("abc  ")  = "abc"
    419         * StringUtils.stripToEmpty(" abc ")  = "abc"
    420         * StringUtils.stripToEmpty(" ab c ") = "ab c"
    421         * </pre>
    422         *
    423         * @param str  the String to be stripped, may be null
    424         * @return the trimmed String, or an empty String if <code>null</code> input
    425         * @since 2.0
    426         */
    427        public static String stripToEmpty(String str) {
    428            return str == null ? EMPTY : strip(str, null);
    429        }
    430
    431        /**
    432         * <p>Strips any of a set of characters from the start and end of a String.
    433         * This is similar to {@link String#trim()} but allows the characters
    434         * to be stripped to be controlled.</p>
    435         *
    436         * <p>A <code>null</code> input String returns <code>null</code>.
    437         * An empty string ("") input returns the empty string.</p>
    438         *
    439         * <p>If the stripChars String is <code>null</code>, whitespace is
    440         * stripped as defined by {@link Character#isWhitespace(char)}.
    441         * Alternatively use {@link #strip(String)}.</p>
    442         *
    443         * <pre>
    444         * StringUtils.strip(null, *)          = null
    445         * StringUtils.strip("", *)            = ""
    446         * StringUtils.strip("abc", null)      = "abc"
    447         * StringUtils.strip("  abc", null)    = "abc"
    448         * StringUtils.strip("abc  ", null)    = "abc"
    449         * StringUtils.strip(" abc ", null)    = "abc"
    450         * StringUtils.strip("  abcyx", "xyz") = "  abc"
    451         * </pre>
    452         *
    453         * @param str  the String to remove characters from, may be null
    454         * @param stripChars  the characters to remove, null treated as whitespace
    455         * @return the stripped String, <code>null</code> if null String input
    456         */
    457        public static String strip(String str, String stripChars) {
    458            if (isEmpty(str)) {
    459                return str;
    460            }
    461            str = stripStart(str, stripChars);
    462            return stripEnd(str, stripChars);
    463        }
    464
    465        /**
    466         * <p>Strips any of a set of characters from the start of a String.</p>
    467         *
    468         * <p>A <code>null</code> input String returns <code>null</code>.
    469         * An empty string ("") input returns the empty string.</p>
    470         *
    471         * <p>If the stripChars String is <code>null</code>, whitespace is
    472         * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    473         *
    474         * <pre>
    475         * StringUtils.stripStart(null, *)          = null
    476         * StringUtils.stripStart("", *)            = ""
    477         * StringUtils.stripStart("abc", "")        = "abc"
    478         * StringUtils.stripStart("abc", null)      = "abc"
    479         * StringUtils.stripStart("  abc", null)    = "abc"
    480         * StringUtils.stripStart("abc  ", null)    = "abc  "
    481         * StringUtils.stripStart(" abc ", null)    = "abc "
    482         * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
    483         * </pre>
    484         *
    485         * @param str  the String to remove characters from, may be null
    486         * @param stripChars  the characters to remove, null treated as whitespace
    487         * @return the stripped String, <code>null</code> if null String input
    488         */
    489        public static String stripStart(String str, String stripChars) {
    490            int strLen;
    491            if (str == null || (strLen = str.length()) == 0) {
    492                return str;
    493            }
    494            int start = 0;
    495            if (stripChars == null) {
    496                while ((start != strLen) && Character.isWhitespace(str.charAt(start))) {
    497                    start++;
    498                }
    499            } else if (stripChars.length() == 0) {
    500                return str;
    501            } else {
    502                while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND)) {
    503                    start++;
    504                }
    505            }
    506            return str.substring(start);
    507        }
    508
    509        /**
    510         * <p>Strips any of a set of characters from the end of a String.</p>
    511         *
    512         * <p>A <code>null</code> input String returns <code>null</code>.
    513         * An empty string ("") input returns the empty string.</p>
    514         *
    515         * <p>If the stripChars String is <code>null</code>, whitespace is
    516         * stripped as defined by {@link Character#isWhitespace(char)}.</p>
    517         *
    518         * <pre>
    519         * StringUtils.stripEnd(null, *)          = null
    520         * StringUtils.stripEnd("", *)            = ""
    521         * StringUtils.stripEnd("abc", "")        = "abc"
    522         * StringUtils.stripEnd("abc", null)      = "abc"
    523         * StringUtils.stripEnd("  abc", null)    = "  abc"
    524         * StringUtils.stripEnd("abc  ", null)    = "abc"
    525         * StringUtils.stripEnd(" abc ", null)    = " abc"
    526         * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
    527         * </pre>
    528         *
    529         * @param str  the String to remove characters from, may be null
    530         * @param stripChars  the characters to remove, null treated as whitespace
    531         * @return the stripped String, <code>null</code> if null String input
    532         */
    533        public static String stripEnd(String str, String stripChars) {
    534            int end;
    535            if (str == null || (end = str.length()) == 0) {
    536                return str;
    537            }
    538
    539            if (stripChars == null) {
    540                while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
    541                    end--;
    542                }
    543            } else if (stripChars.length() == 0) {
    544                return str;
    545            } else {
    546                while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND)) {
    547                    end--;
    548                }
    549            }
    550            return str.substring(0, end);
    551        }
    552
    553        // StripAll
    554        //-----------------------------------------------------------------------
    555        /**
    556         * <p>Strips whitespace from the start and end of every String in an array.
    557         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    558         *
    559         * <p>A new array is returned each time, except for length zero.
    560         * A <code>null</code> array will return <code>null</code>.
    561         * An empty array will return itself.
    562         * A <code>null</code> array entry will be ignored.</p>
    563         *
    564         * <pre>
    565         * StringUtils.stripAll(null)             = null
    566         * StringUtils.stripAll([])               = []
    567         * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
    568         * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
    569         * </pre>
    570         *
    571         * @param strs  the array to remove whitespace from, may be null
    572         * @return the stripped Strings, <code>null</code> if null array input
    573         */
    574        public static String[] stripAll(String[] strs) {
    575            return stripAll(strs, null);
    576        }
    577
    578        /**
    579         * <p>Strips any of a set of characters from the start and end of every
    580         * String in an array.</p>
    581         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    582         *
    583         * <p>A new array is returned each time, except for length zero.
    584         * A <code>null</code> array will return <code>null</code>.
    585         * An empty array will return itself.
    586         * A <code>null</code> array entry will be ignored.
    587         * A <code>null</code> stripChars will strip whitespace as defined by
    588         * {@link Character#isWhitespace(char)}.</p>
    589         *
    590         * <pre>
    591         * StringUtils.stripAll(null, *)                = null
    592         * StringUtils.stripAll([], *)                  = []
    593         * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
    594         * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
    595         * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
    596         * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
    597         * </pre>
    598         *
    599         * @param strs  the array to remove characters from, may be null
    600         * @param stripChars  the characters to remove, null treated as whitespace
    601         * @return the stripped Strings, <code>null</code> if null array input
    602         */
    603        public static String[] stripAll(String[] strs, String stripChars) {
    604            int strsLen;
    605            if (strs == null || (strsLen = strs.length) == 0) {
    606                return strs;
    607            }
    608            String[] newArr = new String[strsLen];
    609            for (int i = 0; i < strsLen; i++) {
    610                newArr[i] = strip(strs[i], stripChars);
    611            }
    612            return newArr;
    613        }
    614
    615        /**
    616         * <p>Removes the accents from a string. </p>
    617         * <p>NOTE: This is a JDK 1.6 method, it will fail on JDK 1.5. </p>
    618         *
    619         * <pre>
    620         * StringUtils.stripAccents(null)                = null
    621         * StringUtils.stripAccents("")                  = ""
    622         * StringUtils.stripAccents("control")           = "control"
    623         * StringUtils.stripAccents("&ecute;clair")      = "eclair"
    624         * </pre>
    625         *
    626         * @param input String to be stripped
    627         * @return String without accents on the text
    628         *
    629         * @since 3.0
    630         */
    631        public static String stripAccents(String input) {
    632            if(input == null) {
    633                return null;
    634            }
    635            if(SystemUtils.isJavaVersionAtLeast(1.6f)) {
    636
    637                // String decomposed = Normalizer.normalize(input, Normalizer.Form.NFD);
    638
    639                // START of 1.5 reflection - in 1.6 use the line commented out above
    640                try {
    641                    // get java.text.Normalizer.Form class
    642                    Class<?> normalizerFormClass = ClassUtils.getClass("java.text.Normalizer$Form", false);
    643
    644                    // get Normlizer class
    645                    Class<?> normalizerClass = ClassUtils.getClass("java.text.Normalizer", false);
    646
    647                    // get static method on Normalizer
    648                    java.lang.reflect.Method method = normalizerClass.getMethod("normalize", CharSequence.class, normalizerFormClass );
    649
    650                    // get Normalizer.NFD field
    651                    java.lang.reflect.Field nfd = normalizerFormClass.getField("NFD");
    652
    653                    // invoke method
    654                    String decomposed = (String) method.invoke( null, input, nfd.get(null) );
    655                    // END of 1.5 reflection
    656
    657                    java.util.regex.Pattern accentPattern = java.util.regex.Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
    658                    return accentPattern.matcher(decomposed).replaceAll("");
    659                } catch(ClassNotFoundException cnfe) {
    660                    throw new RuntimeException("ClassNotFoundException occurred during 1.6 backcompat code", cnfe);
    661                } catch(NoSuchMethodException nsme) {
    662                    throw new RuntimeException("NoSuchMethodException occurred during 1.6 backcompat code", nsme);
    663                } catch(NoSuchFieldException nsfe) {
    664                    throw new RuntimeException("NoSuchFieldException occurred during 1.6 backcompat code", nsfe);
    665                } catch(IllegalAccessException iae) {
    666                    throw new RuntimeException("IllegalAccessException occurred during 1.6 backcompat code", iae);
    667                } catch(IllegalArgumentException iae) {
    668                    throw new RuntimeException("IllegalArgumentException occurred during 1.6 backcompat code", iae);
    669                } catch(java.lang.reflect.InvocationTargetException ite) {
    670                    throw new RuntimeException("InvocationTargetException occurred during 1.6 backcompat code", ite);
    671                } catch(SecurityException se) {
    672                    throw new RuntimeException("SecurityException occurred during 1.6 backcompat code", se);
    673                }
    674            } else {
    675                throw new UnsupportedOperationException("The stripAccents(String) method is not supported until Java 1.6");
    676            }
    677        }
    678
    679        // Equals
    680        //-----------------------------------------------------------------------
    681        /**
    682         * <p>Compares two CharSequences, returning <code>true</code> if they are equal.</p>
    683         *
    684         * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
    685         * references are considered to be equal. The comparison is case sensitive.</p>
    686         *
    687         * <pre>
    688         * StringUtils.equals(null, null)   = true
    689         * StringUtils.equals(null, "abc")  = false
    690         * StringUtils.equals("abc", null)  = false
    691         * StringUtils.equals("abc", "abc") = true
    692         * StringUtils.equals("abc", "ABC") = false
    693         * </pre>
    694         *
    695         * @see java.lang.String#equals(Object)
    696         * @param cs1  the first CharSequence, may be null
    697         * @param cs2  the second CharSequence, may be null
    698         * @return <code>true</code> if the CharSequences are equal, case sensitive, or
    699         *  both <code>null</code>
    700         * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
    701         */
    702        public static boolean equals(CharSequence cs1, CharSequence cs2) {
    703            return cs1 == null ? cs2 == null : cs1.equals(cs2);
    704        }
    705
    706        /**
    707         * <p>Compares two Strings, returning <code>true</code> if they are equal ignoring
    708         * the case.</p>
    709         *
    710         * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
    711         * references are considered equal. Comparison is case insensitive.</p>
    712         *
    713         * <pre>
    714         * StringUtils.equalsIgnoreCase(null, null)   = true
    715         * StringUtils.equalsIgnoreCase(null, "abc")  = false
    716         * StringUtils.equalsIgnoreCase("abc", null)  = false
    717         * StringUtils.equalsIgnoreCase("abc", "abc") = true
    718         * StringUtils.equalsIgnoreCase("abc", "ABC") = true
    719         * </pre>
    720         *
    721         * @see java.lang.String#equalsIgnoreCase(String)
    722         * @param str1  the first String, may be null
    723         * @param str2  the second String, may be null
    724         * @return <code>true</code> if the Strings are equal, case insensitive, or
    725         *  both <code>null</code>
    726         */
    727        public static boolean equalsIgnoreCase(String str1, String str2) {
    728            return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);
    729        }
    730
    731        // IndexOf
    732        //-----------------------------------------------------------------------
    733        /**
    734         * <p>Finds the first index within a String, handling <code>null</code>.
    735         * This method uses {@link String#indexOf(int)}.</p>
    736         *
    737         * <p>A <code>null</code> or empty ("") String will return <code>INDEX_NOT_FOUND (-1)</code>.</p>
    738         *
    739         * <pre>
    740         * StringUtils.indexOf(null, *)         = -1
    741         * StringUtils.indexOf("", *)           = -1
    742         * StringUtils.indexOf("aabaabaa", 'a') = 0
    743         * StringUtils.indexOf("aabaabaa", 'b') = 2
    744         * </pre>
    745         *
    746         * @param str  the String to check, may be null
    747         * @param searchChar  the character to find
    748         * @return the first index of the search character,
    749         *  -1 if no match or <code>null</code> string input
    750         * @since 2.0
    751         */
    752        public static int indexOf(String str, int searchChar) {
    753            if (isEmpty(str)) {
    754                return INDEX_NOT_FOUND;
    755            }
    756            return str.indexOf(searchChar);
    757        }
    758
    759        /**
    760         * <p>Finds the first index within a String from a start position,
    761         * handling <code>null</code>.
    762         * This method uses {@link String#indexOf(int, int)}.</p>
    763         *
    764         * <p>A <code>null</code> or empty ("") String will return <code>(INDEX_NOT_FOUND) -1</code>.
    765         * A negative start position is treated as zero.
    766         * A start position greater than the string length returns <code>-1</code>.</p>
    767         *
    768         * <pre>
    769         * StringUtils.indexOf(null, *, *)          = -1
    770         * StringUtils.indexOf("", *, *)            = -1
    771         * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
    772         * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
    773         * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
    774         * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
    775         * </pre>
    776         *
    777         * @param str  the String to check, may be null
    778         * @param searchChar  the character to find
    779         * @param startPos  the start position, negative treated as zero
    780         * @return the first index of the search character,
    781         *  -1 if no match or <code>null</code> string input
    782         * @since 2.0
    783         */
    784        public static int indexOf(String str, int searchChar, int startPos) {
    785            if (isEmpty(str)) {
    786                return INDEX_NOT_FOUND;
    787            }
    788            return str.indexOf(searchChar, startPos);
    789        }
    790
    791        /**
    792         * <p>Finds the first index within a String, handling <code>null</code>.
    793         * This method uses {@link String#indexOf(String)}.</p>
    794         *
    795         * <p>A <code>null</code> String will return <code>-1</code>.</p>
    796         *
    797         * <pre>
    798         * StringUtils.indexOf(null, *)          = -1
    799         * StringUtils.indexOf(*, null)          = -1
    800         * StringUtils.indexOf("", "")           = 0
    801         * StringUtils.indexOf("", *)            = -1 (except when * = "")
    802         * StringUtils.indexOf("aabaabaa", "a")  = 0
    803         * StringUtils.indexOf("aabaabaa", "b")  = 2
    804         * StringUtils.indexOf("aabaabaa", "ab") = 1
    805         * StringUtils.indexOf("aabaabaa", "")   = 0
    806         * </pre>
    807         *
    808         * @param str  the String to check, may be null
    809         * @param searchStr  the String to find, may be null
    810         * @return the first index of the search String,
    811         *  -1 if no match or <code>null</code> string input
    812         * @since 2.0
    813         */
    814        public static int indexOf(String str, String searchStr) {
    815            if (str == null || searchStr == null) {
    816                return INDEX_NOT_FOUND;
    817            }
    818            return str.indexOf(searchStr);
    819        }
    820
    821        /**
    822         * <p>Finds the first index within a String, handling <code>null</code>.
    823         * This method uses {@link String#indexOf(String, int)}.</p>
    824         *
    825         * <p>A <code>null</code> String will return <code>-1</code>.
    826         * A negative start position is treated as zero.
    827         * An empty ("") search String always matches.
    828         * A start position greater than the string length only matches
    829         * an empty search String.</p>
    830         *
    831         * <pre>
    832         * StringUtils.indexOf(null, *, *)          = -1
    833         * StringUtils.indexOf(*, null, *)          = -1
    834         * StringUtils.indexOf("", "", 0)           = 0
    835         * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
    836         * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
    837         * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
    838         * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
    839         * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
    840         * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
    841         * StringUtils.indexOf("aabaabaa", "b", -1) = 2
    842         * StringUtils.indexOf("aabaabaa", "", 2)   = 2
    843         * StringUtils.indexOf("abc", "", 9)        = 3
    844         * </pre>
    845         *
    846         * @param str  the String to check, may be null
    847         * @param searchStr  the String to find, may be null
    848         * @param startPos  the start position, negative treated as zero
    849         * @return the first index of the search String,
    850         *  -1 if no match or <code>null</code> string input
    851         * @since 2.0
    852         */
    853        public static int indexOf(String str, String searchStr, int startPos) {
    854            if (str == null || searchStr == null) {
    855                return INDEX_NOT_FOUND;
    856            }
    857            return str.indexOf(searchStr, startPos);
    858        }
    859
    860        /**
    861         * <p>Finds the n-th index within a String, handling <code>null</code>.
    862         * This method uses {@link String#indexOf(String)}.</p>
    863         *
    864         * <p>A <code>null</code> String will return <code>-1</code>.</p>
    865         *
    866         * <pre>
    867         * StringUtils.ordinalIndexOf(null, *, *)          = -1
    868         * StringUtils.ordinalIndexOf(*, null, *)          = -1
    869         * StringUtils.ordinalIndexOf("", "", *)           = 0
    870         * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
    871         * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
    872         * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
    873         * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
    874         * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
    875         * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
    876         * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
    877         * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
    878         * </pre>
    879         *
    880         * <p>Note that 'head(String str, int n)' may be implemented as: </p>
    881         *
    882         * <pre>
    883         *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
    884         * </pre>
    885         *
    886         * @param str  the String to check, may be null
    887         * @param searchStr  the String to find, may be null
    888         * @param ordinal  the n-th <code>searchStr</code> to find
    889         * @return the n-th index of the search String,
    890         *  <code>-1</code> (<code>INDEX_NOT_FOUND</code>) if no match or <code>null</code> string input
    891         * @since 2.1
    892         */
    893        public static int ordinalIndexOf(String str, String searchStr, int ordinal) {
    894            return ordinalIndexOf(str, searchStr, ordinal, false);
    895        }
    896
    897        /**
    898         * <p>Finds the n-th index within a String, handling <code>null</code>.
    899         * This method uses {@link String#indexOf(String)}.</p>
    900         *
    901         * <p>A <code>null</code> String will return <code>-1</code>.</p>
    902         *
    903         * @param str  the String to check, may be null
    904         * @param searchStr  the String to find, may be null
    905         * @param ordinal  the n-th <code>searchStr</code> to find
    906         * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
    907         * @return the n-th index of the search String,
    908         *  <code>-1</code> (<code>INDEX_NOT_FOUND</code>) if no match or <code>null</code> string input
    909         */
    910        // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
    911        private static int ordinalIndexOf(String str, String searchStr, int ordinal, boolean lastIndex) {
    912            if (str == null || searchStr == null || ordinal <= 0) {
    913                return INDEX_NOT_FOUND;
    914            }
    915            if (searchStr.length() == 0) {
    916                return lastIndex ? str.length() : 0;
    917            }
    918            int found = 0;
    919            int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
    920            do {
    921                if(lastIndex) {
    922                    index = str.lastIndexOf(searchStr, index - 1);
    923                } else {
    924                    index = str.indexOf(searchStr, index + 1);
    925                }
    926                if (index < 0) {
    927                    return index;
    928                }
    929                found++;
    930            } while (found < ordinal);
    931            return index;
    932        }
    933
    934        /**
    935         * <p>Case in-sensitive find of the first index within a String.</p>
    936         *
    937         * <p>A <code>null</code> String will return <code>-1</code>.
    938         * A negative start position is treated as zero.
    939         * An empty ("") search String always matches.
    940         * A start position greater than the string length only matches
    941         * an empty search String.</p>
    942         *
    943         * <pre>
    944         * StringUtils.indexOfIgnoreCase(null, *)          = -1
    945         * StringUtils.indexOfIgnoreCase(*, null)          = -1
    946         * StringUtils.indexOfIgnoreCase("", "")           = 0
    947         * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
    948         * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
    949         * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
    950         * </pre>
    951         *
    952         * @param str  the String to check, may be null
    953         * @param searchStr  the String to find, may be null
    954         * @return the first index of the search String,
    955         *  -1 if no match or <code>null</code> string input
    956         * @since 2.5
    957         */
    958        public static int indexOfIgnoreCase(String str, String searchStr) {
    959            return indexOfIgnoreCase(str, searchStr, 0);
    960        }
    961
    962        /**
    963         * <p>Case in-sensitive find of the first index within a String
    964         * from the specified position.</p>
    965         *
    966         * <p>A <code>null</code> String will return <code>-1</code>.
    967         * A negative start position is treated as zero.
    968         * An empty ("") search String always matches.
    969         * A start position greater than the string length only matches
    970         * an empty search String.</p>
    971         *
    972         * <pre>
    973         * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
    974         * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
    975         * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
    976         * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    977         * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
    978         * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
    979         * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
    980         * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
    981         * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
    982         * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
    983         * StringUtils.indexOfIgnoreCase("abc", "", 9)        = 3
    984         * </pre>
    985         *
    986         * @param str  the String to check, may be null
    987         * @param searchStr  the String to find, may be null
    988         * @param startPos  the start position, negative treated as zero
    989         * @return the first index of the search String,
    990         *  -1 if no match or <code>null</code> string input
    991         * @since 2.5
    992         */
    993        public static int indexOfIgnoreCase(String str, String searchStr, int startPos) {
    994            if (str == null || searchStr == null) {
    995                return INDEX_NOT_FOUND;
    996            }
    997            if (startPos < 0) {
    998                startPos = 0;
    999            }
    1000            int endLimit = (str.length() - searchStr.length()) + 1;
    1001            if (startPos > endLimit) {
    1002                return INDEX_NOT_FOUND;
    1003            }
    1004            if (searchStr.length() == 0) {
    1005                return startPos;
    1006            }
    1007            for (int i = startPos; i < endLimit; i++) {
    1008                if (str.regionMatches(true, i, searchStr, 0, searchStr.length())) {
    1009                    return i;
    1010                }
    1011            }
    1012            return INDEX_NOT_FOUND;
    1013        }
    1014
    1015        // LastIndexOf
    1016        //-----------------------------------------------------------------------
    1017        /**
    1018         * <p>Finds the last index within a String, handling <code>null</code>.
    1019         * This method uses {@link String#lastIndexOf(int)}.</p>
    1020         *
    1021         * <p>A <code>null</code> or empty ("") String will return <code>-1</code>.</p>
    1022         *
    1023         * <pre>
    1024         * StringUtils.lastIndexOf(null, *)         = -1
    1025         * StringUtils.lastIndexOf("", *)           = -1
    1026         * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
    1027         * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
    1028         * </pre>
    1029         *
    1030         * @param str  the String to check, may be null
    1031         * @param searchChar  the character to find
    1032         * @return the last index of the search character,
    1033         *  -1 if no match or <code>null</code> string input
    1034         * @since 2.0
    1035         */
    1036        public static int lastIndexOf(String str, int searchChar) {
    1037            if (isEmpty(str)) {
    1038                return INDEX_NOT_FOUND;
    1039            }
    1040            return str.lastIndexOf(searchChar);
    1041        }
    1042
    1043        /**
    1044         * <p>Finds the last index within a String from a start position,
    1045         * handling <code>null</code>.
    1046         * This method uses {@link String#lastIndexOf(int, int)}.</p>
    1047         *
    1048         * <p>A <code>null</code> or empty ("") String will return <code>-1</code>.
    1049         * A negative start position returns <code>-1</code>.
    1050         * A start position greater than the string length searches the whole string.</p>
    1051         *
    1052         * <pre>
    1053         * StringUtils.lastIndexOf(null, *, *)          = -1
    1054         * StringUtils.lastIndexOf("", *,  *)           = -1
    1055         * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
    1056         * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
    1057         * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
    1058         * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
    1059         * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
    1060         * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
    1061         * </pre>
    1062         *
    1063         * @param str  the String to check, may be null
    1064         * @param searchChar  the character to find
    1065         * @param startPos  the start position
    1066         * @return the last index of the search character,
    1067         *  -1 if no match or <code>null</code> string input
    1068         * @since 2.0
    1069         */
    1070        public static int lastIndexOf(String str, int searchChar, int startPos) {
    1071            if (isEmpty(str)) {
    1072                return INDEX_NOT_FOUND;
    1073            }
    1074            return str.lastIndexOf(searchChar, startPos);
    1075        }
    1076
    1077        /**
    1078         * <p>Finds the last index within a String, handling <code>null</code>.
    1079         * This method uses {@link String#lastIndexOf(String)}.</p>
    1080         *
    1081         * <p>A <code>null</code> String will return <code>-1</code>.</p>
    1082         *
    1083         * <pre>
    1084         * StringUtils.lastIndexOf(null, *)          = -1
    1085         * StringUtils.lastIndexOf(*, null)          = -1
    1086         * StringUtils.lastIndexOf("", "")           = 0
    1087         * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
    1088         * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
    1089         * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
    1090         * StringUtils.lastIndexOf("aabaabaa", "")   = 8
    1091         * </pre>
    1092         *
    1093         * @param str  the String to check, may be null
    1094         * @param searchStr  the String to find, may be null
    1095         * @return the last index of the search String,
    1096         *  -1 if no match or <code>null</code> string input
    1097         * @since 2.0
    1098         */
    1099        public static int lastIndexOf(String str, String searchStr) {
    1100            if (str == null || searchStr == null) {
    1101                return INDEX_NOT_FOUND;
    1102            }
    1103            return str.lastIndexOf(searchStr);
    1104        }
    1105
    1106        /**
    1107         * <p>Finds the n-th last index within a String, handling <code>null</code>.
    1108         * This method uses {@link String#lastIndexOf(String)}.</p>
    1109         *
    1110         * <p>A <code>null</code> String will return <code>-1</code>.</p>
    1111         *
    1112         * <pre>
    1113         * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
    1114         * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
    1115         * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
    1116         * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
    1117         * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
    1118         * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
    1119         * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
    1120         * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
    1121         * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
    1122         * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
    1123         * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
    1124         * </pre>
    1125         *
    1126         * <p>Note that 'tail(String str, int n)' may be implemented as: </p>
    1127         *
    1128         * <pre>
    1129         *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
    1130         * </pre>
    1131         *
    1132         * @param str  the String to check, may be null
    1133         * @param searchStr  the String to find, may be null
    1134         * @param ordinal  the n-th last <code>searchStr</code> to find
    1135         * @return the n-th last index of the search String,
    1136         *  <code>-1</code> (<code>INDEX_NOT_FOUND</code>) if no match or <code>null</code> string input
    1137         * @since 2.5
    1138         */
    1139        public static int lastOrdinalIndexOf(String str, String searchStr, int ordinal) {
    1140            return ordinalIndexOf(str, searchStr, ordinal, true);
    1141        }
    1142
    1143        /**
    1144         * <p>Finds the first index within a String, handling <code>null</code>.
    1145         * This method uses {@link String#lastIndexOf(String, int)}.</p>
    1146         *
    1147         * <p>A <code>null</code> String will return <code>-1</code>.
    1148         * A negative start position returns <code>-1</code>.
    1149         * An empty ("") search String always matches unless the start position is negative.
    1150         * A start position greater than the string length searches the whole string.</p>
    1151         *
    1152         * <pre>
    1153         * StringUtils.lastIndexOf(null, *, *)          = -1
    1154         * StringUtils.lastIndexOf(*, null, *)          = -1
    1155         * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
    1156         * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
    1157         * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
    1158         * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
    1159         * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
    1160         * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
    1161         * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
    1162         * </pre>
    1163         *
    1164         * @param str  the String to check, may be null
    1165         * @param searchStr  the String to find, may be null
    1166         * @param startPos  the start position, negative treated as zero
    1167         * @return the first index of the search String,
    1168         *  -1 if no match or <code>null</code> string input
    1169         * @since 2.0
    1170         */
    1171        public static int lastIndexOf(String str, String searchStr, int startPos) {
    1172            if (str == null || searchStr == null) {
    1173                return INDEX_NOT_FOUND;
    1174            }
    1175            return str.lastIndexOf(searchStr, startPos);
    1176        }
    1177
    1178        /**
    1179         * <p>Case in-sensitive find of the last index within a String.</p>
    1180         *
    1181         * <p>A <code>null</code> String will return <code>-1</code>.
    1182         * A negative start position returns <code>-1</code>.
    1183         * An empty ("") search String always matches unless the start position is negative.
    1184         * A start position greater than the string length searches the whole string.</p>
    1185         *
    1186         * <pre>
    1187         * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
    1188         * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
    1189         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
    1190         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
    1191         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
    1192         * </pre>
    1193         *
    1194         * @param str  the String to check, may be null
    1195         * @param searchStr  the String to find, may be null
    1196         * @return the first index of the search String,
    1197         *  -1 if no match or <code>null</code> string input
    1198         * @since 2.5
    1199         */
    1200        public static int lastIndexOfIgnoreCase(String str, String searchStr) {
    1201            if (str == null || searchStr == null) {
    1202                return INDEX_NOT_FOUND;
    1203            }
    1204            return lastIndexOfIgnoreCase(str, searchStr, str.length());
    1205        }
    1206
    1207        /**
    1208         * <p>Case in-sensitive find of the last index within a String
    1209         * from the specified position.</p>
    1210         *
    1211         * <p>A <code>null</code> String will return <code>-1</code>.
    1212         * A negative start position returns <code>-1</code>.
    1213         * An empty ("") search String always matches unless the start position is negative.
    1214         * A start position greater than the string length searches the whole string.</p>
    1215         *
    1216         * <pre>
    1217         * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
    1218         * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
    1219         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
    1220         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
    1221         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
    1222         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
    1223         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
    1224         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
    1225         * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
    1226         * </pre>
    1227         *
    1228         * @param str  the String to check, may be null
    1229         * @param searchStr  the String to find, may be null
    1230         * @param startPos  the start position
    1231         * @return the first index of the search String,
    1232         *  -1 if no match or <code>null</code> string input
    1233         * @since 2.5
    1234         */
    1235        public static int lastIndexOfIgnoreCase(String str, String searchStr, int startPos) {
    1236            if (str == null || searchStr == null) {
    1237                return INDEX_NOT_FOUND;
    1238            }
    1239            if (startPos > (str.length() - searchStr.length())) {
    1240                startPos = str.length() - searchStr.length();
    1241            }
    1242            if (startPos < 0) {
    1243                return INDEX_NOT_FOUND;
    1244            }
    1245            if (searchStr.length() == 0) {
    1246                return startPos;
    1247            }
    1248
    1249            for (int i = startPos; i >= 0; i--) {
    1250                if (str.regionMatches(true, i, searchStr, 0, searchStr.length())) {
    1251                    return i;
    1252                }
    1253            }
    1254            return INDEX_NOT_FOUND;
    1255        }
    1256
    1257        // Contains
    1258        //-----------------------------------------------------------------------
    1259        /**
    1260         * <p>Checks if String contains a search character, handling <code>null</code>.
    1261         * This method uses {@link String#indexOf(int)}.</p>
    1262         *
    1263         * <p>A <code>null</code> or empty ("") String will return <code>false</code>.</p>
    1264         *
    1265         * <pre>
    1266         * StringUtils.contains(null, *)    = false
    1267         * StringUtils.contains("", *)      = false
    1268         * StringUtils.contains("abc", 'a') = true
    1269         * StringUtils.contains("abc", 'z') = false
    1270         * </pre>
    1271         *
    1272         * @param str  the String to check, may be null
    1273         * @param searchChar  the character to find
    1274         * @return true if the String contains the search character,
    1275         *  false if not or <code>null</code> string input
    1276         * @since 2.0
    1277         */
    1278        public static boolean contains(String str, int searchChar) {
    1279            if (isEmpty(str)) {
    1280                return false;
    1281            }
    1282            return str.indexOf(searchChar) >= 0;
    1283        }
    1284
    1285        /**
    1286         * <p>Checks if String contains a search String, handling <code>null</code>.
    1287         * This method uses {@link String#indexOf(String)}.</p>
    1288         *
    1289         * <p>A <code>null</code> String will return <code>false</code>.</p>
    1290         *
    1291         * <pre>
    1292         * StringUtils.contains(null, *)     = false
    1293         * StringUtils.contains(*, null)     = false
    1294         * StringUtils.contains("", "")      = true
    1295         * StringUtils.contains("abc", "")   = true
    1296         * StringUtils.contains("abc", "a")  = true
    1297         * StringUtils.contains("abc", "z")  = false
    1298         * </pre>
    1299         *
    1300         * @param str  the String to check, may be null
    1301         * @param searchStr  the String to find, may be null
    1302         * @return true if the String contains the search String,
    1303         *  false if not or <code>null</code> string input
    1304         * @since 2.0
    1305         */
    1306        public static boolean contains(String str, String searchStr) {
    1307            if (str == null || searchStr == null) {
    1308                return false;
    1309            }
    1310            return str.indexOf(searchStr) >= 0;
    1311        }
    1312
    1313        /**
    1314         * <p>Checks if String contains a search String irrespective of case,
    1315         * handling <code>null</code>. Case-insensitivity is defined as by
    1316         * {@link String#equalsIgnoreCase(String)}.
    1317         *
    1318         * <p>A <code>null</code> String will return <code>false</code>.</p>
    1319         *
    1320         * <pre>
    1321         * StringUtils.contains(null, *) = false
    1322         * StringUtils.contains(*, null) = false
    1323         * StringUtils.contains("", "") = true
    1324         * StringUtils.contains("abc", "") = true
    1325         * StringUtils.contains("abc", "a") = true
    1326         * StringUtils.contains("abc", "z") = false
    1327         * StringUtils.contains("abc", "A") = true
    1328         * StringUtils.contains("abc", "Z") = false
    1329         * </pre>
    1330         *
    1331         * @param str  the String to check, may be null
    1332         * @param searchStr  the String to find, may be null
    1333         * @return true if the String contains the search String irrespective of
    1334         * case or false if not or <code>null</code> string input
    1335         */
    1336        public static boolean containsIgnoreCase(String str, String searchStr) {
    1337            if (str == null || searchStr == null) {
    1338                return false;
    1339            }
    1340            int len = searchStr.length();
    1341            int max = str.length() - len;
    1342            for (int i = 0; i <= max; i++) {
    1343                if (str.regionMatches(true, i, searchStr, 0, len)) {
    1344                    return true;
    1345                }
    1346            }
    1347            return false;
    1348        }
    1349
    1350        /**
    1351         * Check whether the given String contains any whitespace characters.
    1352         * @param str the String to check (may be <code>null</code>)
    1353         * @return <code>true</code> if the String is not empty and
    1354         * contains at least 1 whitespace character
    1355         * @see java.lang.Character#isWhitespace
    1356         * @since 3.0
    1357         */
    1358        // From org.springframework.util.StringUtils, under Apache License 2.0
    1359        public static boolean containsWhitespace(String str) {
    1360            if (isEmpty(str)) {
    1361                return false;
    1362            }
    1363            int strLen = str.length();
    1364            for (int i = 0; i < strLen; i++) {
    1365                if (Character.isWhitespace(str.charAt(i))) {
    1366                    return true;
    1367                }
    1368            }
    1369            return false;
    1370        }
    1371
    1372        // IndexOfAny chars
    1373        //-----------------------------------------------------------------------
    1374        /**
    1375         * <p>Search a CharSequence to find the first index of any
    1376         * character in the given set of characters.</p>
    1377         *
    1378         * <p>A <code>null</code> String will return <code>-1</code>.
    1379         * A <code>null</code> or zero length search array will return <code>-1</code>.</p>
    1380         *
    1381         * <pre>
    1382         * StringUtils.indexOfAny(null, *)                = -1
    1383         * StringUtils.indexOfAny("", *)                  = -1
    1384         * StringUtils.indexOfAny(*, null)                = -1
    1385         * StringUtils.indexOfAny(*, [])                  = -1
    1386         * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
    1387         * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
    1388         * StringUtils.indexOfAny("aba", ['z'])           = -1
    1389         * </pre>
    1390         *
    1391         * @param cs  the CharSequence to check, may be null
    1392         * @param searchChars  the chars to search for, may be null
    1393         * @return the index of any of the chars, -1 if no match or null input
    1394         * @since 2.0
    1395         * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char[])
    1396         */
    1397        public static int indexOfAny(CharSequence cs, char[] searchChars) {
    1398            if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1399                return INDEX_NOT_FOUND;
    1400            }
    1401            int csLen = cs.length();
    1402            int csLast = csLen - 1;
    1403            int searchLen = searchChars.length;
    1404            int searchLast = searchLen - 1;
    1405            for (int i = 0; i < csLen; i++) {
    1406                char ch = cs.charAt(i);
    1407                for (int j = 0; j < searchLen; j++) {
    1408                    if (searchChars[j] == ch) {
    1409                        if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
    1410                            // ch is a supplementary character
    1411                            if (searchChars[j + 1] == cs.charAt(i + 1)) {
    1412                                return i;
    1413                            }
    1414                        } else {
    1415                            return i;
    1416                        }
    1417                    }
    1418                }
    1419            }
    1420            return INDEX_NOT_FOUND;
    1421        }
    1422
    1423        /**
    1424         * <p>Search a CharSequence to find the first index of any
    1425         * character in the given set of characters.</p>
    1426         *
    1427         * <p>A <code>null</code> String will return <code>-1</code>.
    1428         * A <code>null</code> search string will return <code>-1</code>.</p>
    1429         *
    1430         * <pre>
    1431         * StringUtils.indexOfAny(null, *)            = -1
    1432         * StringUtils.indexOfAny("", *)              = -1
    1433         * StringUtils.indexOfAny(*, null)            = -1
    1434         * StringUtils.indexOfAny(*, "")              = -1
    1435         * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
    1436         * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
    1437         * StringUtils.indexOfAny("aba","z")          = -1
    1438         * </pre>
    1439         *
    1440         * @param cs  the CharSequence to check, may be null
    1441         * @param searchChars  the chars to search for, may be null
    1442         * @return the index of any of the chars, -1 if no match or null input
    1443         * @since 2.0
    1444         * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
    1445         */
    1446        public static int indexOfAny(CharSequence cs, String searchChars) {
    1447            if (isEmpty(cs) || isEmpty(searchChars)) {
    1448                return INDEX_NOT_FOUND;
    1449            }
    1450            return indexOfAny(cs, searchChars.toCharArray());
    1451        }
    1452
    1453        // ContainsAny
    1454        //-----------------------------------------------------------------------
    1455        /**
    1456         * <p>Checks if the CharSequence contains any character in the given
    1457         * set of characters.</p>
    1458         *
    1459         * <p>A <code>null</code> CharSequence will return <code>false</code>.
    1460         * A <code>null</code> or zero length search array will return <code>false</code>.</p>
    1461         *
    1462         * <pre>
    1463         * StringUtils.containsAny(null, *)                = false
    1464         * StringUtils.containsAny("", *)                  = false
    1465         * StringUtils.containsAny(*, null)                = false
    1466         * StringUtils.containsAny(*, [])                  = false
    1467         * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
    1468         * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
    1469         * StringUtils.containsAny("aba", ['z'])           = false
    1470         * </pre>
    1471         *
    1472         * @param cs  the CharSequence to check, may be null
    1473         * @param searchChars  the chars to search for, may be null
    1474         * @return the <code>true</code> if any of the chars are found,
    1475         * <code>false</code> if no match or null input
    1476         * @since 2.4
    1477         */
    1478        public static boolean containsAny(String cs, char[] searchChars) {
    1479            if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1480                return false;
    1481            }
    1482            int csLength = cs.length();
    1483            int searchLength = searchChars.length;
    1484            int csLast = csLength - 1;
    1485            int searchLast = searchLength - 1;
    1486            for (int i = 0; i < csLength; i++) {
    1487                char ch = cs.charAt(i);
    1488                for (int j = 0; j < searchLength; j++) {
    1489                    if (searchChars[j] == ch) {
    1490                        if (Character.isHighSurrogate(ch)) {
    1491                            if (j == searchLast) {
    1492                                // missing low surrogate, fine, like String.indexOf(String)
    1493                                return true;
    1494                            }
    1495                            if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1496                                return true;
    1497                            }
    1498                        } else {
    1499                            // ch is in the Basic Multilingual Plane
    1500                            return true;
    1501                        }
    1502                    }
    1503                }
    1504            }
    1505            return false;
    1506        }
    1507
    1508        /**
    1509         * <p>
    1510         * Checks if the CharSequence contains any character in the given set of characters.
    1511         * </p>
    1512         *
    1513         * <p>
    1514         * A <code>null</code> CharSequence will return <code>false</code>. A <code>null</code> search CharSequence will return
    1515         * <code>false</code>.
    1516         * </p>
    1517         *
    1518         * <pre>
    1519         * StringUtils.containsAny(null, *)            = false
    1520         * StringUtils.containsAny("", *)              = false
    1521         * StringUtils.containsAny(*, null)            = false
    1522         * StringUtils.containsAny(*, "")              = false
    1523         * StringUtils.containsAny("zzabyycdxx", "za") = true
    1524         * StringUtils.containsAny("zzabyycdxx", "by") = true
    1525         * StringUtils.containsAny("aba","z")          = false
    1526         * </pre>
    1527         *
    1528         * @param cs
    1529         *            the CharSequence to check, may be null
    1530         * @param searchChars
    1531         *            the chars to search for, may be null
    1532         * @return the <code>true</code> if any of the chars are found, <code>false</code> if no match or null input
    1533         * @since 2.4
    1534         */
    1535        public static boolean containsAny(String cs, String searchChars) {
    1536            if (searchChars == null) {
    1537                return false;
    1538            }
    1539            return containsAny(cs, searchChars.toCharArray());
    1540        }
    1541
    1542        // IndexOfAnyBut chars
    1543        //-----------------------------------------------------------------------
    1544        /**
    1545         * <p>Searches a CharSequence to find the first index of any
    1546         * character not in the given set of characters.</p>
    1547         *
    1548         * <p>A <code>null</code> CharSequence will return <code>-1</code>.
    1549         * A <code>null</code> or zero length search array will return <code>-1</code>.</p>
    1550         *
    1551         * <pre>
    1552         * StringUtils.indexOfAnyBut(null, *)           = -1
    1553         * StringUtils.indexOfAnyBut("", *)             = -1
    1554         * StringUtils.indexOfAnyBut(*, null)           = -1
    1555         * StringUtils.indexOfAnyBut(*, [])             = -1
    1556         * StringUtils.indexOfAnyBut("zzabyycdxx",'za') = 3
    1557         * StringUtils.indexOfAnyBut("zzabyycdxx", '')  = 0
    1558         * StringUtils.indexOfAnyBut("aba", 'ab')       = -1
    1559         * </pre>
    1560         *
    1561         * @param cs  the CharSequence to check, may be null
    1562         * @param searchChars  the chars to search for, may be null
    1563         * @return the index of any of the chars, -1 if no match or null input
    1564         * @since 2.0
    1565         * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char[])
    1566         */
    1567        public static int indexOfAnyBut(CharSequence cs, char[] searchChars) {
    1568            if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
    1569                return INDEX_NOT_FOUND;
    1570            }
    1571            int csLen = cs.length();
    1572            int csLast = csLen - 1;
    1573            int searchLen = searchChars.length;
    1574            int searchLast = searchLen - 1;
    1575            outer:
    1576            for (int i = 0; i < csLen; i++) {
    1577                char ch = cs.charAt(i);
    1578                for (int j = 0; j < searchLen; j++) {
    1579                    if (searchChars[j] == ch) {
    1580                        if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
    1581                            if (searchChars[j + 1] == cs.charAt(i + 1)) {
    1582                                continue outer;
    1583                            }
    1584                        } else {
    1585                            continue outer;
    1586                        }
    1587                    }
    1588                }
    1589                return i;
    1590            }
    1591            return INDEX_NOT_FOUND;
    1592        }
    1593
    1594        /**
    1595         * <p>Search a String to find the first index of any
    1596         * character not in the given set of characters.</p>
    1597         *
    1598         * <p>A <code>null</code> String will return <code>-1</code>.
    1599         * A <code>null</code> search string will return <code>-1</code>.</p>
    1600         *
    1601         * <pre>
    1602         * StringUtils.indexOfAnyBut(null, *)            = -1
    1603         * StringUtils.indexOfAnyBut("", *)              = -1
    1604         * StringUtils.indexOfAnyBut(*, null)            = -1
    1605         * StringUtils.indexOfAnyBut(*, "")              = -1
    1606         * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
    1607         * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = 0
    1608         * StringUtils.indexOfAnyBut("aba","ab")         = -1
    1609         * </pre>
    1610         *
    1611         * @param str  the String to check, may be null
    1612         * @param searchChars  the chars to search for, may be null
    1613         * @return the index of any of the chars, -1 if no match or null input
    1614         * @since 2.0
    1615         */
    1616        public static int indexOfAnyBut(String str, String searchChars) {
    1617            if (isEmpty(str) || isEmpty(searchChars)) {
    1618                return INDEX_NOT_FOUND;
    1619            }
    1620            int strLen = str.length();
    1621            for (int i = 0; i < strLen; i++) {
    1622                char ch = str.charAt(i);
    1623                boolean chFound = searchChars.indexOf(ch) >= 0;
    1624                if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
    1625                    char ch2 = str.charAt(i + 1);
    1626                    if (chFound && searchChars.indexOf(ch2) < 0) {
    1627                        return i;
    1628                    }
    1629                } else {
    1630                    if (!chFound) {
    1631                        return i;
    1632                    }
    1633                }
    1634            }
    1635            return INDEX_NOT_FOUND;
    1636        }
    1637
    1638        // ContainsOnly
    1639        //-----------------------------------------------------------------------
    1640        /**
    1641         * <p>Checks if the CharSequence contains only certain characters.</p>
    1642         *
    1643         * <p>A <code>null</code> CharSequence will return <code>false</code>.
    1644         * A <code>null</code> valid character array will return <code>false</code>.
    1645         * An empty CharSequence (length()=0) always returns <code>true</code>.</p>
    1646         *
    1647         * <pre>
    1648         * StringUtils.containsOnly(null, *)       = false
    1649         * StringUtils.containsOnly(*, null)       = false
    1650         * StringUtils.containsOnly("", *)         = true
    1651         * StringUtils.containsOnly("ab", '')      = false
    1652         * StringUtils.containsOnly("abab", 'abc') = true
    1653         * StringUtils.containsOnly("ab1", 'abc')  = false
    1654         * StringUtils.containsOnly("abz", 'abc')  = false
    1655         * </pre>
    1656         *
    1657         * @param cs  the String to check, may be null
    1658         * @param valid  an array of valid chars, may be null
    1659         * @return true if it only contains valid chars and is non-null
    1660         * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char[])
    1661         */
    1662        public static boolean containsOnly(CharSequence cs, char[] valid) {
    1663            // All these pre-checks are to maintain API with an older version
    1664            if (valid == null || cs == null) {
    1665                return false;
    1666            }
    1667            if (cs.length() == 0) {
    1668                return true;
    1669            }
    1670            if (valid.length == 0) {
    1671                return false;
    1672            }
    1673            return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
    1674        }
    1675
    1676        /**
    1677         * <p>Checks if the CharSequence contains only certain characters.</p>
    1678         *
    1679         * <p>A <code>null</code> CharSequence will return <code>false</code>.
    1680         * A <code>null</code> valid character String will return <code>false</code>.
    1681         * An empty String (length()=0) always returns <code>true</code>.</p>
    1682         *
    1683         * <pre>
    1684         * StringUtils.containsOnly(null, *)       = false
    1685         * StringUtils.containsOnly(*, null)       = false
    1686         * StringUtils.containsOnly("", *)         = true
    1687         * StringUtils.containsOnly("ab", "")      = false
    1688         * StringUtils.containsOnly("abab", "abc") = true
    1689         * StringUtils.containsOnly("ab1", "abc")  = false
    1690         * StringUtils.containsOnly("abz", "abc")  = false
    1691         * </pre>
    1692         *
    1693         * @param cs  the CharSequence to check, may be null
    1694         * @param validChars  a String of valid chars, may be null
    1695         * @return true if it only contains valid chars and is non-null
    1696         * @since 2.0
    1697         * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
    1698         */
    1699        public static boolean containsOnly(CharSequence cs, String validChars) {
    1700            if (cs == null || validChars == null) {
    1701                return false;
    1702            }
    1703            return containsOnly(cs, validChars.toCharArray());
    1704        }
    1705
    1706        // ContainsNone
    1707        //-----------------------------------------------------------------------
    1708        /**
    1709         * <p>Checks that the CharSequence does not contain certain characters.</p>
    1710         *
    1711         * <p>A <code>null</code> CharSequence will return <code>true</code>.
    1712         * A <code>null</code> invalid character array will return <code>true</code>.
    1713         * An empty CharSequence (length()=0) always returns true.</p>
    1714         *
    1715         * <pre>
    1716         * StringUtils.containsNone(null, *)       = true
    1717         * StringUtils.containsNone(*, null)       = true
    1718         * StringUtils.containsNone("", *)         = true
    1719         * StringUtils.containsNone("ab", '')      = true
    1720         * StringUtils.containsNone("abab", 'xyz') = true
    1721         * StringUtils.containsNone("ab1", 'xyz')  = true
    1722         * StringUtils.containsNone("abz", 'xyz')  = false
    1723         * </pre>
    1724         *
    1725         * @param cs  the CharSequence to check, may be null
    1726         * @param searchChars  an array of invalid chars, may be null
    1727         * @return true if it contains none of the invalid chars, or is null
    1728         * @since 2.0
    1729         * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char[])
    1730         */
    1731        public static boolean containsNone(CharSequence cs, char[] searchChars) {
    1732            if (cs == null || searchChars == null) {
    1733                return true;
    1734            }
    1735            int csLen = cs.length();
    1736            int csLast = csLen - 1;
    1737            int searchLen = searchChars.length;
    1738            int searchLast = searchLen - 1;
    1739            for (int i = 0; i < csLen; i++) {
    1740                char ch = cs.charAt(i);
    1741                for (int j = 0; j < searchLen; j++) {
    1742                    if (searchChars[j] == ch) {
    1743                        if (Character.isHighSurrogate(ch)) {
    1744                            if (j == searchLast) {
    1745                                // missing low surrogate, fine, like String.indexOf(String)
    1746                                return false;
    1747                            }
    1748                            if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
    1749                                return false;
    1750                            }
    1751                        } else {
    1752                            // ch is in the Basic Multilingual Plane
    1753                            return false;
    1754                        }
    1755                    }
    1756                }
    1757            }
    1758            return true;
    1759        }
    1760
    1761        /**
    1762         * <p>Checks that the CharSequence does not contain certain characters.</p>
    1763         *
    1764         * <p>A <code>null</code> CharSequence will return <code>true</code>.
    1765         * A <code>null</code> invalid character array will return <code>true</code>.
    1766         * An empty String ("") always returns true.</p>
    1767         *
    1768         * <pre>
    1769         * StringUtils.containsNone(null, *)       = true
    1770         * StringUtils.containsNone(*, null)       = true
    1771         * StringUtils.containsNone("", *)         = true
    1772         * StringUtils.containsNone("ab", "")      = true
    1773         * StringUtils.containsNone("abab", "xyz") = true
    1774         * StringUtils.containsNone("ab1", "xyz")  = true
    1775         * StringUtils.containsNone("abz", "xyz")  = false
    1776         * </pre>
    1777         *
    1778         * @param cs  the CharSequence to check, may be null
    1779         * @param invalidChars  a String of invalid chars, may be null
    1780         * @return true if it contains none of the invalid chars, or is null
    1781         * @since 2.0
    1782         * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
    1783         */
    1784        public static boolean containsNone(CharSequence cs, String invalidChars) {
    1785            if (cs == null || invalidChars == null) {
    1786                return true;
    1787            }
    1788            return containsNone(cs, invalidChars.toCharArray());
    1789        }
    1790
    1791        // IndexOfAny strings
    1792        //-----------------------------------------------------------------------
    1793        /**
    1794         * <p>Find the first index of any of a set of potential substrings.</p>
    1795         *
    1796         * <p>A <code>null</code> String will return <code>-1</code>.
    1797         * A <code>null</code> or zero length search array will return <code>-1</code>.
    1798         * A <code>null</code> search array entry will be ignored, but a search
    1799         * array containing "" will return <code>0</code> if <code>str</code> is not
    1800         * null. This method uses {@link String#indexOf(String)}.</p>
    1801         *
    1802         * <pre>
    1803         * StringUtils.indexOfAny(null, *)                     = -1
    1804         * StringUtils.indexOfAny(*, null)                     = -1
    1805         * StringUtils.indexOfAny(*, [])                       = -1
    1806         * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"])   = 2
    1807         * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"])   = 2
    1808         * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"])   = -1
    1809         * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
    1810         * StringUtils.indexOfAny("zzabyycdxx", [""])          = 0
    1811         * StringUtils.indexOfAny("", [""])                    = 0
    1812         * StringUtils.indexOfAny("", ["a"])                   = -1
    1813         * </pre>
    1814         *
    1815         * @param str  the String to check, may be null
    1816         * @param searchStrs  the Strings to search for, may be null
    1817         * @return the first index of any of the searchStrs in str, -1 if no match
    1818         */
    1819        public static int indexOfAny(String str, String[] searchStrs) {
    1820            if (str == null || searchStrs == null) {
    1821                return INDEX_NOT_FOUND;
    1822            }
    1823            int sz = searchStrs.length;
    1824
    1825            // String's can't have a MAX_VALUEth index.
    1826            int ret = Integer.MAX_VALUE;
    1827
    1828            int tmp = 0;
    1829            for (int i = 0; i < sz; i++) {
    1830                String search = searchStrs[i];
    1831                if (search == null) {
    1832                    continue;
    1833                }
    1834                tmp = str.indexOf(search);
    1835                if (tmp == INDEX_NOT_FOUND) {
    1836                    continue;
    1837                }
    1838
    1839                if (tmp < ret) {
    1840                    ret = tmp;
    1841                }
    1842            }
    1843
    1844            return (ret == Integer.MAX_VALUE) ? INDEX_NOT_FOUND : ret;
    1845        }
    1846
    1847        /**
    1848         * <p>Find the latest index of any of a set of potential substrings.</p>
    1849         *
    1850         * <p>A <code>null</code> String will return <code>-1</code>.
    1851         * A <code>null</code> search array will return <code>-1</code>.
    1852         * A <code>null</code> or zero length search array entry will be ignored,
    1853         * but a search array containing "" will return the length of <code>str</code>
    1854         * if <code>str</code> is not null. This method uses {@link String#indexOf(String)}</p>
    1855         *
    1856         * <pre>
    1857         * StringUtils.lastIndexOfAny(null, *)                   = -1
    1858         * StringUtils.lastIndexOfAny(*, null)                   = -1
    1859         * StringUtils.lastIndexOfAny(*, [])                     = -1
    1860         * StringUtils.lastIndexOfAny(*, [null])                 = -1
    1861         * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
    1862         * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
    1863         * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
    1864         * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
    1865         * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""])   = 10
    1866         * </pre>
    1867         *
    1868         * @param str  the String to check, may be null
    1869         * @param searchStrs  the Strings to search for, may be null
    1870         * @return the last index of any of the Strings, -1 if no match
    1871         */
    1872        public static int lastIndexOfAny(String str, String[] searchStrs) {
    1873            if (str == null || searchStrs == null) {
    1874                return INDEX_NOT_FOUND;
    1875            }
    1876            int sz = searchStrs.length;
    1877            int ret = INDEX_NOT_FOUND;
    1878            int tmp = 0;
    1879            for (int i = 0; i < sz; i++) {
    1880                String search = searchStrs[i];
    1881                if (search == null) {
    1882                    continue;
    1883                }
    1884                tmp = str.lastIndexOf(search);
    1885                if (tmp > ret) {
    1886                    ret = tmp;
    1887                }
    1888            }
    1889            return ret;
    1890        }
    1891
    1892        // Substring
    1893        //-----------------------------------------------------------------------
    1894        /**
    1895         * <p>Gets a substring from the specified String avoiding exceptions.</p>
    1896         *
    1897         * <p>A negative start position can be used to start <code>n</code>
    1898         * characters from the end of the String.</p>
    1899         *
    1900         * <p>A <code>null</code> String will return <code>null</code>.
    1901         * An empty ("") String will return "".</p>
    1902         *
    1903         * <pre>
    1904         * StringUtils.substring(null, *)   = null
    1905         * StringUtils.substring("", *)     = ""
    1906         * StringUtils.substring("abc", 0)  = "abc"
    1907         * StringUtils.substring("abc", 2)  = "c"
    1908         * StringUtils.substring("abc", 4)  = ""
    1909         * StringUtils.substring("abc", -2) = "bc"
    1910         * StringUtils.substring("abc", -4) = "abc"
    1911         * </pre>
    1912         *
    1913         * @param str  the String to get the substring from, may be null
    1914         * @param start  the position to start from, negative means
    1915         *  count back from the end of the String by this many characters
    1916         * @return substring from start position, <code>null</code> if null String input
    1917         */
    1918        public static String substring(String str, int start) {
    1919            if (str == null) {
    1920                return null;
    1921            }
    1922
    1923            // handle negatives, which means last n characters
    1924            if (start < 0) {
    1925                start = str.length() + start; // remember start is negative
    1926            }
    1927
    1928            if (start < 0) {
    1929                start = 0;
    1930            }
    1931            if (start > str.length()) {
    1932                return EMPTY;
    1933            }
    1934
    1935            return str.substring(start);
    1936        }
    1937
    1938        /**
    1939         * <p>Gets a substring from the specified String avoiding exceptions.</p>
    1940         *
    1941         * <p>A negative start position can be used to start/end <code>n</code>
    1942         * characters from the end of the String.</p>
    1943         *
    1944         * <p>The returned substring starts with the character in the <code>start</code>
    1945         * position and ends before the <code>end</code> position. All position counting is
    1946         * zero-based -- i.e., to start at the beginning of the string use
    1947         * <code>start = 0</code>. Negative start and end positions can be used to
    1948         * specify offsets relative to the end of the String.</p>
    1949         *
    1950         * <p>If <code>start</code> is not strictly to the left of <code>end</code>, ""
    1951         * is returned.</p>
    1952         *
    1953         * <pre>
    1954         * StringUtils.substring(null, *, *)    = null
    1955         * StringUtils.substring("", * ,  *)    = "";
    1956         * StringUtils.substring("abc", 0, 2)   = "ab"
    1957         * StringUtils.substring("abc", 2, 0)   = ""
    1958         * StringUtils.substring("abc", 2, 4)   = "c"
    1959         * StringUtils.substring("abc", 4, 6)   = ""
    1960         * StringUtils.substring("abc", 2, 2)   = ""
    1961         * StringUtils.substring("abc", -2, -1) = "b"
    1962         * StringUtils.substring("abc", -4, 2)  = "ab"
    1963         * </pre>
    1964         *
    1965         * @param str  the String to get the substring from, may be null
    1966         * @param start  the position to start from, negative means
    1967         *  count back from the end of the String by this many characters
    1968         * @param end  the position to end at (exclusive), negative means
    1969         *  count back from the end of the String by this many characters
    1970         * @return substring from start position to end positon,
    1971         *  <code>null</code> if null String input
    1972         */
    1973        public static String substring(String str, int start, int end) {
    1974            if (str == null) {
    1975                return null;
    1976            }
    1977
    1978            // handle negatives
    1979            if (end < 0) {
    1980                end = str.length() + end; // remember end is negative
    1981            }
    1982            if (start < 0) {
    1983                start = str.length() + start; // remember start is negative
    1984            }
    1985
    1986            // check length next
    1987            if (end > str.length()) {
    1988                end = str.length();
    1989            }
    1990
    1991            // if start is greater than end, return ""
    1992            if (start > end) {
    1993                return EMPTY;
    1994            }
    1995
    1996            if (start < 0) {
    1997                start = 0;
    1998            }
    1999            if (end < 0) {
    2000                end = 0;
    2001            }
    2002
    2003            return str.substring(start, end);
    2004        }
    2005
    2006        // Left/Right/Mid
    2007        //-----------------------------------------------------------------------
    2008        /**
    2009         * <p>Gets the leftmost <code>len</code> characters of a String.</p>
    2010         *
    2011         * <p>If <code>len</code> characters are not available, or the
    2012         * String is <code>null</code>, the String will be returned without
    2013         * an exception. An exception is thrown if len is negative.</p>
    2014         *
    2015         * <pre>
    2016         * StringUtils.left(null, *)    = null
    2017         * StringUtils.left(*, -ve)     = ""
    2018         * StringUtils.left("", *)      = ""
    2019         * StringUtils.left("abc", 0)   = ""
    2020         * StringUtils.left("abc", 2)   = "ab"
    2021         * StringUtils.left("abc", 4)   = "abc"
    2022         * </pre>
    2023         *
    2024         * @param str  the String to get the leftmost characters from, may be null
    2025         * @param len  the length of the required String, must be zero or positive
    2026         * @return the leftmost characters, <code>null</code> if null String input
    2027         */
    2028        public static String left(String str, int len) {
    2029            if (str == null) {
    2030                return null;
    2031            }
    2032            if (len < 0) {
    2033                return EMPTY;
    2034            }
    2035            if (str.length() <= len) {
    2036                return str;
    2037            }
    2038            return str.substring(0, len);
    2039        }
    2040
    2041        /**
    2042         * <p>Gets the rightmost <code>len</code> characters of a String.</p>
    2043         *
    2044         * <p>If <code>len</code> characters are not available, or the String
    2045         * is <code>null</code>, the String will be returned without an
    2046         * an exception. An exception is thrown if len is negative.</p>
    2047         *
    2048         * <pre>
    2049         * StringUtils.right(null, *)    = null
    2050         * StringUtils.right(*, -ve)     = ""
    2051         * StringUtils.right("", *)      = ""
    2052         * StringUtils.right("abc", 0)   = ""
    2053         * StringUtils.right("abc", 2)   = "bc"
    2054         * StringUtils.right("abc", 4)   = "abc"
    2055         * </pre>
    2056         *
    2057         * @param str  the String to get the rightmost characters from, may be null
    2058         * @param len  the length of the required String, must be zero or positive
    2059         * @return the rightmost characters, <code>null</code> if null String input
    2060         */
    2061        public static String right(String str, int len) {
    2062            if (str == null) {
    2063                return null;
    2064            }
    2065            if (len < 0) {
    2066                return EMPTY;
    2067            }
    2068            if (str.length() <= len) {
    2069                return str;
    2070            }
    2071            return str.substring(str.length() - len);
    2072        }
    2073
    2074        /**
    2075         * <p>Gets <code>len</code> characters from the middle of a String.</p>
    2076         *
    2077         * <p>If <code>len</code> characters are not available, the remainder
    2078         * of the String will be returned without an exception. If the
    2079         * String is <code>null</code>, <code>null</code> will be returned.
    2080         * An exception is thrown if len is negative.</p>
    2081         *
    2082         * <pre>
    2083         * StringUtils.mid(null, *, *)    = null
    2084         * StringUtils.mid(*, *, -ve)     = ""
    2085         * StringUtils.mid("", 0, *)      = ""
    2086         * StringUtils.mid("abc", 0, 2)   = "ab"
    2087         * StringUtils.mid("abc", 0, 4)   = "abc"
    2088         * StringUtils.mid("abc", 2, 4)   = "c"
    2089         * StringUtils.mid("abc", 4, 2)   = ""
    2090         * StringUtils.mid("abc", -2, 2)  = "ab"
    2091         * </pre>
    2092         *
    2093         * @param str  the String to get the characters from, may be null
    2094         * @param pos  the position to start from, negative treated as zero
    2095         * @param len  the length of the required String, must be zero or positive
    2096         * @return the middle characters, <code>null</code> if null String input
    2097         */
    2098        public static String mid(String str, int pos, int len) {
    2099            if (str == null) {
    2100                return null;
    2101            }
    2102            if (len < 0 || pos > str.length()) {
    2103                return EMPTY;
    2104            }
    2105            if (pos < 0) {
    2106                pos = 0;
    2107            }
    2108            if (str.length() <= (pos + len)) {
    2109                return str.substring(pos);
    2110            }
    2111            return str.substring(pos, pos + len);
    2112        }
    2113
    2114        // SubStringAfter/SubStringBefore
    2115        //-----------------------------------------------------------------------
    2116        /**
    2117         * <p>Gets the substring before the first occurrence of a separator.
    2118         * The separator is not returned.</p>
    2119         *
    2120         * <p>A <code>null</code> string input will return <code>null</code>.
    2121         * An empty ("") string input will return the empty string.
    2122         * A <code>null</code> separator will return the input string.</p>
    2123         *
    2124         * <p>If nothing is found, the string input is returned.</p>
    2125         *
    2126         * <pre>
    2127         * StringUtils.substringBefore(null, *)      = null
    2128         * StringUtils.substringBefore("", *)        = ""
    2129         * StringUtils.substringBefore("abc", "a")   = ""
    2130         * StringUtils.substringBefore("abcba", "b") = "a"
    2131         * StringUtils.substringBefore("abc", "c")   = "ab"
    2132         * StringUtils.substringBefore("abc", "d")   = "abc"
    2133         * StringUtils.substringBefore("abc", "")    = ""
    2134         * StringUtils.substringBefore("abc", null)  = "abc"
    2135         * </pre>
    2136         *
    2137         * @param str  the String to get a substring from, may be null
    2138         * @param separator  the String to search for, may be null
    2139         * @return the substring before the first occurrence of the separator,
    2140         *  <code>null</code> if null String input
    2141         * @since 2.0
    2142         */
    2143        public static String substringBefore(String str, String separator) {
    2144            if (isEmpty(str) || separator == null) {
    2145                return str;
    2146            }
    2147            if (separator.length() == 0) {
    2148                return EMPTY;
    2149            }
    2150            int pos = str.indexOf(separator);
    2151            if (pos == INDEX_NOT_FOUND) {
    2152                return str;
    2153            }
    2154            return str.substring(0, pos);
    2155        }
    2156
    2157        /**
    2158         * <p>Gets the substring after the first occurrence of a separator.
    2159         * The separator is not returned.</p>
    2160         *
    2161         * <p>A <code>null</code> string input will return <code>null</code>.
    2162         * An empty ("") string input will return the empty string.
    2163         * A <code>null</code> separator will return the empty string if the
    2164         * input string is not <code>null</code>.</p>
    2165         *
    2166         * <p>If nothing is found, the empty string is returned.</p>
    2167         *
    2168         * <pre>
    2169         * StringUtils.substringAfter(null, *)      = null
    2170         * StringUtils.substringAfter("", *)        = ""
    2171         * StringUtils.substringAfter(*, null)      = ""
    2172         * StringUtils.substringAfter("abc", "a")   = "bc"
    2173         * StringUtils.substringAfter("abcba", "b") = "cba"
    2174         * StringUtils.substringAfter("abc", "c")   = ""
    2175         * StringUtils.substringAfter("abc", "d")   = ""
    2176         * StringUtils.substringAfter("abc", "")    = "abc"
    2177         * </pre>
    2178         *
    2179         * @param str  the String to get a substring from, may be null
    2180         * @param separator  the String to search for, may be null
    2181         * @return the substring after the first occurrence of the separator,
    2182         *  <code>null</code> if null String input
    2183         * @since 2.0
    2184         */
    2185        public static String substringAfter(String str, String separator) {
    2186            if (isEmpty(str)) {
    2187                return str;
    2188            }
    2189            if (separator == null) {
    2190                return EMPTY;
    2191            }
    2192            int pos = str.indexOf(separator);
    2193            if (pos == INDEX_NOT_FOUND) {
    2194                return EMPTY;
    2195            }
    2196            return str.substring(pos + separator.length());
    2197        }
    2198
    2199        /**
    2200         * <p>Gets the substring before the last occurrence of a separator.
    2201         * The separator is not returned.</p>
    2202         *
    2203         * <p>A <code>null</code> string input will return <code>null</code>.
    2204         * An empty ("") string input will return the empty string.
    2205         * An empty or <code>null</code> separator will return the input string.</p>
    2206         *
    2207         * <p>If nothing is found, the string input is returned.</p>
    2208         *
    2209         * <pre>
    2210         * StringUtils.substringBeforeLast(null, *)      = null
    2211         * StringUtils.substringBeforeLast("", *)        = ""
    2212         * StringUtils.substringBeforeLast("abcba", "b") = "abc"
    2213         * StringUtils.substringBeforeLast("abc", "c")   = "ab"
    2214         * StringUtils.substringBeforeLast("a", "a")     = ""
    2215         * StringUtils.substringBeforeLast("a", "z")     = "a"
    2216         * StringUtils.substringBeforeLast("a", null)    = "a"
    2217         * StringUtils.substringBeforeLast("a", "")      = "a"
    2218         * </pre>
    2219         *
    2220         * @param str  the String to get a substring from, may be null
    2221         * @param separator  the String to search for, may be null
    2222         * @return the substring before the last occurrence of the separator,
    2223         *  <code>null</code> if null String input
    2224         * @since 2.0
    2225         */
    2226        public static String substringBeforeLast(String str, String separator) {
    2227            if (isEmpty(str) || isEmpty(separator)) {
    2228                return str;
    2229            }
    2230            int pos = str.lastIndexOf(separator);
    2231            if (pos == INDEX_NOT_FOUND) {
    2232                return str;
    2233            }
    2234            return str.substring(0, pos);
    2235        }
    2236
    2237        /**
    2238         * <p>Gets the substring after the last occurrence of a separator.
    2239         * The separator is not returned.</p>
    2240         *
    2241         * <p>A <code>null</code> string input will return <code>null</code>.
    2242         * An empty ("") string input will return the empty string.
    2243         * An empty or <code>null</code> separator will return the empty string if
    2244         * the input string is not <code>null</code>.</p>
    2245         *
    2246         * <p>If nothing is found, the empty string is returned.</p>
    2247         *
    2248         * <pre>
    2249         * StringUtils.substringAfterLast(null, *)      = null
    2250         * StringUtils.substringAfterLast("", *)        = ""
    2251         * StringUtils.substringAfterLast(*, "")        = ""
    2252         * StringUtils.substringAfterLast(*, null)      = ""
    2253         * StringUtils.substringAfterLast("abc", "a")   = "bc"
    2254         * StringUtils.substringAfterLast("abcba", "b") = "a"
    2255         * StringUtils.substringAfterLast("abc", "c")   = ""
    2256         * StringUtils.substringAfterLast("a", "a")     = ""
    2257         * StringUtils.substringAfterLast("a", "z")     = ""
    2258         * </pre>
    2259         *
    2260         * @param str  the String to get a substring from, may be null
    2261         * @param separator  the String to search for, may be null
    2262         * @return the substring after the last occurrence of the separator,
    2263         *  <code>null</code> if null String input
    2264         * @since 2.0
    2265         */
    2266        public static String substringAfterLast(String str, String separator) {
    2267            if (isEmpty(str)) {
    2268                return str;
    2269            }
    2270            if (isEmpty(separator)) {
    2271                return EMPTY;
    2272            }
    2273            int pos = str.lastIndexOf(separator);
    2274            if (pos == INDEX_NOT_FOUND || pos == (str.length() - separator.length())) {
    2275                return EMPTY;
    2276            }
    2277            return str.substring(pos + separator.length());
    2278        }
    2279
    2280        // Substring between
    2281        //-----------------------------------------------------------------------
    2282        /**
    2283         * <p>Gets the String that is nested in between two instances of the
    2284         * same String.</p>
    2285         *
    2286         * <p>A <code>null</code> input String returns <code>null</code>.
    2287         * A <code>null</code> tag returns <code>null</code>.</p>
    2288         *
    2289         * <pre>
    2290         * StringUtils.substringBetween(null, *)            = null
    2291         * StringUtils.substringBetween("", "")             = ""
    2292         * StringUtils.substringBetween("", "tag")          = null
    2293         * StringUtils.substringBetween("tagabctag", null)  = null
    2294         * StringUtils.substringBetween("tagabctag", "")    = ""
    2295         * StringUtils.substringBetween("tagabctag", "tag") = "abc"
    2296         * </pre>
    2297         *
    2298         * @param str  the String containing the substring, may be null
    2299         * @param tag  the String before and after the substring, may be null
    2300         * @return the substring, <code>null</code> if no match
    2301         * @since 2.0
    2302         */
    2303        public static String substringBetween(String str, String tag) {
    2304            return substringBetween(str, tag, tag);
    2305        }
    2306
    2307        /**
    2308         * <p>Gets the String that is nested in between two Strings.
    2309         * Only the first match is returned.</p>
    2310         *
    2311         * <p>A <code>null</code> input String returns <code>null</code>.
    2312         * A <code>null</code> open/close returns <code>null</code> (no match).
    2313         * An empty ("") open and close returns an empty string.</p>
    2314         *
    2315         * <pre>
    2316         * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
    2317         * StringUtils.substringBetween(null, *, *)          = null
    2318         * StringUtils.substringBetween(*, null, *)          = null
    2319         * StringUtils.substringBetween(*, *, null)          = null
    2320         * StringUtils.substringBetween("", "", "")          = ""
    2321         * StringUtils.substringBetween("", "", "]")         = null
    2322         * StringUtils.substringBetween("", "[", "]")        = null
    2323         * StringUtils.substringBetween("yabcz", "", "")     = ""
    2324         * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
    2325         * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
    2326         * </pre>
    2327         *
    2328         * @param str  the String containing the substring, may be null
    2329         * @param open  the String before the substring, may be null
    2330         * @param close  the String after the substring, may be null
    2331         * @return the substring, <code>null</code> if no match
    2332         * @since 2.0
    2333         */
    2334        public static String substringBetween(String str, String open, String close) {
    2335            if (str == null || open == null || close == null) {
    2336                return null;
    2337            }
    2338            int start = str.indexOf(open);
    2339            if (start != INDEX_NOT_FOUND) {
    2340                int end = str.indexOf(close, start + open.length());
    2341                if (end != INDEX_NOT_FOUND) {
    2342                    return str.substring(start + open.length(), end);
    2343                }
    2344            }
    2345            return null;
    2346        }
    2347
    2348        /**
    2349         * <p>Searches a String for substrings delimited by a start and end tag,
    2350         * returning all matching substrings in an array.</p>
    2351         *
    2352         * <p>A <code>null</code> input String returns <code>null</code>.
    2353         * A <code>null</code> open/close returns <code>null</code> (no match).
    2354         * An empty ("") open/close returns <code>null</code> (no match).</p>
    2355         *
    2356         * <pre>
    2357         * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
    2358         * StringUtils.substringsBetween(null, *, *)            = null
    2359         * StringUtils.substringsBetween(*, null, *)            = null
    2360         * StringUtils.substringsBetween(*, *, null)            = null
    2361         * StringUtils.substringsBetween("", "[", "]")          = []
    2362         * </pre>
    2363         *
    2364         * @param str  the String containing the substrings, null returns null, empty returns empty
    2365         * @param open  the String identifying the start of the substring, empty returns null
    2366         * @param close  the String identifying the end of the substring, empty returns null
    2367         * @return a String Array of substrings, or <code>null</code> if no match
    2368         * @since 2.3
    2369         */
    2370        public static String[] substringsBetween(String str, String open, String close) {
    2371            if (str == null || isEmpty(open) || isEmpty(close)) {
    2372                return null;
    2373            }
    2374            int strLen = str.length();
    2375            if (strLen == 0) {
    2376                return ArrayUtils.EMPTY_STRING_ARRAY;
    2377            }
    2378            int closeLen = close.length();
    2379            int openLen = open.length();
    2380            List<String> list = new ArrayList<String>();
    2381            int pos = 0;
    2382            while (pos < (strLen - closeLen)) {
    2383                int start = str.indexOf(open, pos);
    2384                if (start < 0) {
    2385                    break;
    2386                }
    2387                start += openLen;
    2388                int end = str.indexOf(close, start);
    2389                if (end < 0) {
    2390                    break;
    2391                }
    2392                list.add(str.substring(start, end));
    2393                pos = end + closeLen;
    2394            }
    2395            if (list.isEmpty()) {
    2396                return null;
    2397            }
    2398            return list.toArray(new String [list.size()]);
    2399        }
    2400
    2401        // Nested extraction
    2402        //-----------------------------------------------------------------------
    2403
    2404        // Splitting
    2405        //-----------------------------------------------------------------------
    2406        /**
    2407         * <p>Splits the provided text into an array, using whitespace as the
    2408         * separator.
    2409         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    2410         *
    2411         * <p>The separator is not included in the returned String array.
    2412         * Adjacent separators are treated as one separator.
    2413         * For more control over the split use the StrTokenizer class.</p>
    2414         *
    2415         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    2416         *
    2417         * <pre>
    2418         * StringUtils.split(null)       = null
    2419         * StringUtils.split("")         = []
    2420         * StringUtils.split("abc def")  = ["abc", "def"]
    2421         * StringUtils.split("abc  def") = ["abc", "def"]
    2422         * StringUtils.split(" abc ")    = ["abc"]
    2423         * </pre>
    2424         *
    2425         * @param str  the String to parse, may be null
    2426         * @return an array of parsed Strings, <code>null</code> if null String input
    2427         */
    2428        public static String[] split(String str) {
    2429            return split(str, null, -1);
    2430        }
    2431
    2432        /**
    2433         * <p>Splits the provided text into an array, separator specified.
    2434         * This is an alternative to using StringTokenizer.</p>
    2435         *
    2436         * <p>The separator is not included in the returned String array.
    2437         * Adjacent separators are treated as one separator.
    2438         * For more control over the split use the StrTokenizer class.</p>
    2439         *
    2440         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    2441         *
    2442         * <pre>
    2443         * StringUtils.split(null, *)         = null
    2444         * StringUtils.split("", *)           = []
    2445         * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
    2446         * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
    2447         * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
    2448         * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
    2449         * </pre>
    2450         *
    2451         * @param str  the String to parse, may be null
    2452         * @param separatorChar  the character used as the delimiter
    2453         * @return an array of parsed Strings, <code>null</code> if null String input
    2454         * @since 2.0
    2455         */
    2456        public static String[] split(String str, char separatorChar) {
    2457            return splitWorker(str, separatorChar, false);
    2458        }
    2459
    2460        /**
    2461         * <p>Splits the provided text into an array, separators specified.
    2462         * This is an alternative to using StringTokenizer.</p>
    2463         *
    2464         * <p>The separator is not included in the returned String array.
    2465         * Adjacent separators are treated as one separator.
    2466         * For more control over the split use the StrTokenizer class.</p>
    2467         *
    2468         * <p>A <code>null</code> input String returns <code>null</code>.
    2469         * A <code>null</code> separatorChars splits on whitespace.</p>
    2470         *
    2471         * <pre>
    2472         * StringUtils.split(null, *)         = null
    2473         * StringUtils.split("", *)           = []
    2474         * StringUtils.split("abc def", null) = ["abc", "def"]
    2475         * StringUtils.split("abc def", " ")  = ["abc", "def"]
    2476         * StringUtils.split("abc  def", " ") = ["abc", "def"]
    2477         * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
    2478         * </pre>
    2479         *
    2480         * @param str  the String to parse, may be null
    2481         * @param separatorChars  the characters used as the delimiters,
    2482         *  <code>null</code> splits on whitespace
    2483         * @return an array of parsed Strings, <code>null</code> if null String input
    2484         */
    2485        public static String[] split(String str, String separatorChars) {
    2486            return splitWorker(str, separatorChars, -1, false);
    2487        }
    2488
    2489        /**
    2490         * <p>Splits the provided text into an array with a maximum length,
    2491         * separators specified.</p>
    2492         *
    2493         * <p>The separator is not included in the returned String array.
    2494         * Adjacent separators are treated as one separator.</p>
    2495         *
    2496         * <p>A <code>null</code> input String returns <code>null</code>.
    2497         * A <code>null</code> separatorChars splits on whitespace.</p>
    2498         *
    2499         * <p>If more than <code>max</code> delimited substrings are found, the last
    2500         * returned string includes all characters after the first <code>max - 1</code>
    2501         * returned strings (including separator characters).</p>
    2502         *
    2503         * <pre>
    2504         * StringUtils.split(null, *, *)            = null
    2505         * StringUtils.split("", *, *)              = []
    2506         * StringUtils.split("ab de fg", null, 0)   = ["ab", "cd", "ef"]
    2507         * StringUtils.split("ab   de fg", null, 0) = ["ab", "cd", "ef"]
    2508         * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    2509         * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    2510         * </pre>
    2511         *
    2512         * @param str  the String to parse, may be null
    2513         * @param separatorChars  the characters used as the delimiters,
    2514         *  <code>null</code> splits on whitespace
    2515         * @param max  the maximum number of elements to include in the
    2516         *  array. A zero or negative value implies no limit
    2517         * @return an array of parsed Strings, <code>null</code> if null String input
    2518         */
    2519        public static String[] split(String str, String separatorChars, int max) {
    2520            return splitWorker(str, separatorChars, max, false);
    2521        }
    2522
    2523        /**
    2524         * <p>Splits the provided text into an array, separator string specified.</p>
    2525         *
    2526         * <p>The separator(s) will not be included in the returned String array.
    2527         * Adjacent separators are treated as one separator.</p>
    2528         *
    2529         * <p>A <code>null</code> input String returns <code>null</code>.
    2530         * A <code>null</code> separator splits on whitespace.</p>
    2531         *
    2532         * <pre>
    2533         * StringUtils.splitByWholeSeparator(null, *)               = null
    2534         * StringUtils.splitByWholeSeparator("", *)                 = []
    2535         * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
    2536         * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
    2537         * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    2538         * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    2539         * </pre>
    2540         *
    2541         * @param str  the String to parse, may be null
    2542         * @param separator  String containing the String to be used as a delimiter,
    2543         *  <code>null</code> splits on whitespace
    2544         * @return an array of parsed Strings, <code>null</code> if null String was input
    2545         */
    2546        public static String[] splitByWholeSeparator(String str, String separator) {
    2547            return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
    2548        }
    2549
    2550        /**
    2551         * <p>Splits the provided text into an array, separator string specified.
    2552         * Returns a maximum of <code>max</code> substrings.</p>
    2553         *
    2554         * <p>The separator(s) will not be included in the returned String array.
    2555         * Adjacent separators are treated as one separator.</p>
    2556         *
    2557         * <p>A <code>null</code> input String returns <code>null</code>.
    2558         * A <code>null</code> separator splits on whitespace.</p>
    2559         *
    2560         * <pre>
    2561         * StringUtils.splitByWholeSeparator(null, *, *)               = null
    2562         * StringUtils.splitByWholeSeparator("", *, *)                 = []
    2563         * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
    2564         * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
    2565         * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    2566         * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    2567         * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    2568         * </pre>
    2569         *
    2570         * @param str  the String to parse, may be null
    2571         * @param separator  String containing the String to be used as a delimiter,
    2572         *  <code>null</code> splits on whitespace
    2573         * @param max  the maximum number of elements to include in the returned
    2574         *  array. A zero or negative value implies no limit.
    2575         * @return an array of parsed Strings, <code>null</code> if null String was input
    2576         */
    2577        public static String[] splitByWholeSeparator( String str, String separator, int max ) {
    2578            return splitByWholeSeparatorWorker(str, separator, max, false);
    2579        }
    2580
    2581        /**
    2582         * <p>Splits the provided text into an array, separator string specified. </p>
    2583         *
    2584         * <p>The separator is not included in the returned String array.
    2585         * Adjacent separators are treated as separators for empty tokens.
    2586         * For more control over the split use the StrTokenizer class.</p>
    2587         *
    2588         * <p>A <code>null</code> input String returns <code>null</code>.
    2589         * A <code>null</code> separator splits on whitespace.</p>
    2590         *
    2591         * <pre>
    2592         * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
    2593         * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
    2594         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
    2595         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
    2596         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
    2597         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
    2598         * </pre>
    2599         *
    2600         * @param str  the String to parse, may be null
    2601         * @param separator  String containing the String to be used as a delimiter,
    2602         *  <code>null</code> splits on whitespace
    2603         * @return an array of parsed Strings, <code>null</code> if null String was input
    2604         * @since 2.4
    2605         */
    2606        public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
    2607            return splitByWholeSeparatorWorker(str, separator, -1, true);
    2608        }
    2609
    2610        /**
    2611         * <p>Splits the provided text into an array, separator string specified.
    2612         * Returns a maximum of <code>max</code> substrings.</p>
    2613         *
    2614         * <p>The separator is not included in the returned String array.
    2615         * Adjacent separators are treated as separators for empty tokens.
    2616         * For more control over the split use the StrTokenizer class.</p>
    2617         *
    2618         * <p>A <code>null</code> input String returns <code>null</code>.
    2619         * A <code>null</code> separator splits on whitespace.</p>
    2620         *
    2621         * <pre>
    2622         * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
    2623         * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
    2624         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
    2625         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
    2626         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
    2627         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
    2628         * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
    2629         * </pre>
    2630         *
    2631         * @param str  the String to parse, may be null
    2632         * @param separator  String containing the String to be used as a delimiter,
    2633         *  <code>null</code> splits on whitespace
    2634         * @param max  the maximum number of elements to include in the returned
    2635         *  array. A zero or negative value implies no limit.
    2636         * @return an array of parsed Strings, <code>null</code> if null String was input
    2637         * @since 2.4
    2638         */
    2639        public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) {
    2640            return splitByWholeSeparatorWorker(str, separator, max, true);
    2641        }
    2642
    2643        /**
    2644         * Performs the logic for the <code>splitByWholeSeparatorPreserveAllTokens</code> methods.
    2645         *
    2646         * @param str  the String to parse, may be <code>null</code>
    2647         * @param separator  String containing the String to be used as a delimiter,
    2648         *  <code>null</code> splits on whitespace
    2649         * @param max  the maximum number of elements to include in the returned
    2650         *  array. A zero or negative value implies no limit.
    2651         * @param preserveAllTokens if <code>true</code>, adjacent separators are
    2652         * treated as empty token separators; if <code>false</code>, adjacent
    2653         * separators are treated as one separator.
    2654         * @return an array of parsed Strings, <code>null</code> if null String input
    2655         * @since 2.4
    2656         */
    2657        private static String[] splitByWholeSeparatorWorker(String str, String separator, int max,
    2658                                                            boolean preserveAllTokens)
    2659        {
    2660            if (str == null) {
    2661                return null;
    2662            }
    2663
    2664            int len = str.length();
    2665
    2666            if (len == 0) {
    2667                return ArrayUtils.EMPTY_STRING_ARRAY;
    2668            }
    2669
    2670            if ((separator == null) || (EMPTY.equals(separator))) {
    2671                // Split on whitespace.
    2672                return splitWorker(str, null, max, preserveAllTokens);
    2673            }
    2674
    2675            int separatorLength = separator.length();
    2676
    2677            ArrayList<String> substrings = new ArrayList<String>();
    2678            int numberOfSubstrings = 0;
    2679            int beg = 0;
    2680            int end = 0;
    2681            while (end < len) {
    2682                end = str.indexOf(separator, beg);
    2683
    2684                if (end > -1) {
    2685                    if (end > beg) {
    2686                        numberOfSubstrings += 1;
    2687
    2688                        if (numberOfSubstrings == max) {
    2689                            end = len;
    2690                            substrings.add(str.substring(beg));
    2691                        } else {
    2692                            // The following is OK, because String.substring( beg, end ) excludes
    2693                            // the character at the position 'end'.
    2694                            substrings.add(str.substring(beg, end));
    2695
    2696                            // Set the starting point for the next search.
    2697                            // The following is equivalent to beg = end + (separatorLength - 1) + 1,
    2698                            // which is the right calculation:
    2699                            beg = end + separatorLength;
    2700                        }
    2701                    } else {
    2702                        // We found a consecutive occurrence of the separator, so skip it.
    2703                        if (preserveAllTokens) {
    2704                            numberOfSubstrings += 1;
    2705                            if (numberOfSubstrings == max) {
    2706                                end = len;
    2707                                substrings.add(str.substring(beg));
    2708                            } else {
    2709                                substrings.add(EMPTY);
    2710                            }
    2711                        }
    2712                        beg = end + separatorLength;
    2713                    }
    2714                } else {
    2715                    // String.substring( beg ) goes from 'beg' to the end of the String.
    2716                    substrings.add(str.substring(beg));
    2717                    end = len;
    2718                }
    2719            }
    2720
    2721            return substrings.toArray(new String[substrings.size()]);
    2722        }
    2723
    2724        // -----------------------------------------------------------------------
    2725        /**
    2726         * <p>Splits the provided text into an array, using whitespace as the
    2727         * separator, preserving all tokens, including empty tokens created by
    2728         * adjacent separators. This is an alternative to using StringTokenizer.
    2729         * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
    2730         *
    2731         * <p>The separator is not included in the returned String array.
    2732         * Adjacent separators are treated as separators for empty tokens.
    2733         * For more control over the split use the StrTokenizer class.</p>
    2734         *
    2735         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    2736         *
    2737         * <pre>
    2738         * StringUtils.splitPreserveAllTokens(null)       = null
    2739         * StringUtils.splitPreserveAllTokens("")         = []
    2740         * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
    2741         * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
    2742         * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
    2743         * </pre>
    2744         *
    2745         * @param str  the String to parse, may be <code>null</code>
    2746         * @return an array of parsed Strings, <code>null</code> if null String input
    2747         * @since 2.1
    2748         */
    2749        public static String[] splitPreserveAllTokens(String str) {
    2750            return splitWorker(str, null, -1, true);
    2751        }
    2752
    2753        /**
    2754         * <p>Splits the provided text into an array, separator specified,
    2755         * preserving all tokens, including empty tokens created by adjacent
    2756         * separators. This is an alternative to using StringTokenizer.</p>
    2757         *
    2758         * <p>The separator is not included in the returned String array.
    2759         * Adjacent separators are treated as separators for empty tokens.
    2760         * For more control over the split use the StrTokenizer class.</p>
    2761         *
    2762         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    2763         *
    2764         * <pre>
    2765         * StringUtils.splitPreserveAllTokens(null, *)         = null
    2766         * StringUtils.splitPreserveAllTokens("", *)           = []
    2767         * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
    2768         * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
    2769         * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
    2770         * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
    2771         * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
    2772         * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
    2773         * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
    2774         * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
    2775         * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
    2776         * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
    2777         * </pre>
    2778         *
    2779         * @param str  the String to parse, may be <code>null</code>
    2780         * @param separatorChar  the character used as the delimiter,
    2781         *  <code>null</code> splits on whitespace
    2782         * @return an array of parsed Strings, <code>null</code> if null String input
    2783         * @since 2.1
    2784         */
    2785        public static String[] splitPreserveAllTokens(String str, char separatorChar) {
    2786            return splitWorker(str, separatorChar, true);
    2787        }
    2788
    2789        /**
    2790         * Performs the logic for the <code>split</code> and
    2791         * <code>splitPreserveAllTokens</code> methods that do not return a
    2792         * maximum array length.
    2793         *
    2794         * @param str  the String to parse, may be <code>null</code>
    2795         * @param separatorChar the separate character
    2796         * @param preserveAllTokens if <code>true</code>, adjacent separators are
    2797         * treated as empty token separators; if <code>false</code>, adjacent
    2798         * separators are treated as one separator.
    2799         * @return an array of parsed Strings, <code>null</code> if null String input
    2800         */
    2801        private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) {
    2802            // Performance tuned for 2.0 (JDK1.4)
    2803
    2804            if (str == null) {
    2805                return null;
    2806            }
    2807            int len = str.length();
    2808            if (len == 0) {
    2809                return ArrayUtils.EMPTY_STRING_ARRAY;
    2810            }
    2811            List<String> list = new ArrayList<String>();
    2812            int i = 0, start = 0;
    2813            boolean match = false;
    2814            boolean lastMatch = false;
    2815            while (i < len) {
    2816                if (str.charAt(i) == separatorChar) {
    2817                    if (match || preserveAllTokens) {
    2818                        list.add(str.substring(start, i));
    2819                        match = false;
    2820                        lastMatch = true;
    2821                    }
    2822                    start = ++i;
    2823                    continue;
    2824                }
    2825                lastMatch = false;
    2826                match = true;
    2827                i++;
    2828            }
    2829            if (match || (preserveAllTokens && lastMatch)) {
    2830                list.add(str.substring(start, i));
    2831            }
    2832            return list.toArray(new String[list.size()]);
    2833        }
    2834
    2835        /**
    2836         * <p>Splits the provided text into an array, separators specified,
    2837         * preserving all tokens, including empty tokens created by adjacent
    2838         * separators. This is an alternative to using StringTokenizer.</p>
    2839         *
    2840         * <p>The separator is not included in the returned String array.
    2841         * Adjacent separators are treated as separators for empty tokens.
    2842         * For more control over the split use the StrTokenizer class.</p>
    2843         *
    2844         * <p>A <code>null</code> input String returns <code>null</code>.
    2845         * A <code>null</code> separatorChars splits on whitespace.</p>
    2846         *
    2847         * <pre>
    2848         * StringUtils.splitPreserveAllTokens(null, *)           = null
    2849         * StringUtils.splitPreserveAllTokens("", *)             = []
    2850         * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
    2851         * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
    2852         * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
    2853         * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
    2854         * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
    2855         * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
    2856         * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
    2857         * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
    2858         * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
    2859         * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
    2860         * </pre>
    2861         *
    2862         * @param str  the String to parse, may be <code>null</code>
    2863         * @param separatorChars  the characters used as the delimiters,
    2864         *  <code>null</code> splits on whitespace
    2865         * @return an array of parsed Strings, <code>null</code> if null String input
    2866         * @since 2.1
    2867         */
    2868        public static String[] splitPreserveAllTokens(String str, String separatorChars) {
    2869            return splitWorker(str, separatorChars, -1, true);
    2870        }
    2871
    2872        /**
    2873         * <p>Splits the provided text into an array with a maximum length,
    2874         * separators specified, preserving all tokens, including empty tokens
    2875         * created by adjacent separators.</p>
    2876         *
    2877         * <p>The separator is not included in the returned String array.
    2878         * Adjacent separators are treated as separators for empty tokens.
    2879         * Adjacent separators are treated as one separator.</p>
    2880         *
    2881         * <p>A <code>null</code> input String returns <code>null</code>.
    2882         * A <code>null</code> separatorChars splits on whitespace.</p>
    2883         *
    2884         * <p>If more than <code>max</code> delimited substrings are found, the last
    2885         * returned string includes all characters after the first <code>max - 1</code>
    2886         * returned strings (including separator characters).</p>
    2887         *
    2888         * <pre>
    2889         * StringUtils.splitPreserveAllTokens(null, *, *)            = null
    2890         * StringUtils.splitPreserveAllTokens("", *, *)              = []
    2891         * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
    2892         * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
    2893         * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
    2894         * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
    2895         * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
    2896         * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
    2897         * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
    2898         * </pre>
    2899         *
    2900         * @param str  the String to parse, may be <code>null</code>
    2901         * @param separatorChars  the characters used as the delimiters,
    2902         *  <code>null</code> splits on whitespace
    2903         * @param max  the maximum number of elements to include in the
    2904         *  array. A zero or negative value implies no limit
    2905         * @return an array of parsed Strings, <code>null</code> if null String input
    2906         * @since 2.1
    2907         */
    2908        public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
    2909            return splitWorker(str, separatorChars, max, true);
    2910        }
    2911
    2912        /**
    2913         * Performs the logic for the <code>split</code> and
    2914         * <code>splitPreserveAllTokens</code> methods that return a maximum array
    2915         * length.
    2916         *
    2917         * @param str  the String to parse, may be <code>null</code>
    2918         * @param separatorChars the separate character
    2919         * @param max  the maximum number of elements to include in the
    2920         *  array. A zero or negative value implies no limit.
    2921         * @param preserveAllTokens if <code>true</code>, adjacent separators are
    2922         * treated as empty token separators; if <code>false</code>, adjacent
    2923         * separators are treated as one separator.
    2924         * @return an array of parsed Strings, <code>null</code> if null String input
    2925         */
    2926        private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
    2927            // Performance tuned for 2.0 (JDK1.4)
    2928            // Direct code is quicker than StringTokenizer.
    2929            // Also, StringTokenizer uses isSpace() not isWhitespace()
    2930
    2931            if (str == null) {
    2932                return null;
    2933            }
    2934            int len = str.length();
    2935            if (len == 0) {
    2936                return ArrayUtils.EMPTY_STRING_ARRAY;
    2937            }
    2938            List<String> list = new ArrayList<String>();
    2939            int sizePlus1 = 1;
    2940            int i = 0, start = 0;
    2941            boolean match = false;
    2942            boolean lastMatch = false;
    2943            if (separatorChars == null) {
    2944                // Null separator means use whitespace
    2945                while (i < len) {
    2946                    if (Character.isWhitespace(str.charAt(i))) {
    2947                        if (match || preserveAllTokens) {
    2948                            lastMatch = true;
    2949                            if (sizePlus1++ == max) {
    2950                                i = len;
    2951                                lastMatch = false;
    2952                            }
    2953                            list.add(str.substring(start, i));
    2954                            match = false;
    2955                        }
    2956                        start = ++i;
    2957                        continue;
    2958                    }
    2959                    lastMatch = false;
    2960                    match = true;
    2961                    i++;
    2962                }
    2963            } else if (separatorChars.length() == 1) {
    2964                // Optimise 1 character case
    2965                char sep = separatorChars.charAt(0);
    2966                while (i < len) {
    2967                    if (str.charAt(i) == sep) {
    2968                        if (match || preserveAllTokens) {
    2969                            lastMatch = true;
    2970                            if (sizePlus1++ == max) {
    2971                                i = len;
    2972                                lastMatch = false;
    2973                            }
    2974                            list.add(str.substring(start, i));
    2975                            match = false;
    2976                        }
    2977                        start = ++i;
    2978                        continue;
    2979                    }
    2980                    lastMatch = false;
    2981                    match = true;
    2982                    i++;
    2983                }
    2984            } else {
    2985                // standard case
    2986                while (i < len) {
    2987                    if (separatorChars.indexOf(str.charAt(i)) >= 0) {
    2988                        if (match || preserveAllTokens) {
    2989                            lastMatch = true;
    2990                            if (sizePlus1++ == max) {
    2991                                i = len;
    2992                                lastMatch = false;
    2993                            }
    2994                            list.add(str.substring(start, i));
    2995                            match = false;
    2996                        }
    2997                        start = ++i;
    2998                        continue;
    2999                    }
    3000                    lastMatch = false;
    3001                    match = true;
    3002                    i++;
    3003                }
    3004            }
    3005            if (match || (preserveAllTokens && lastMatch)) {
    3006                list.add(str.substring(start, i));
    3007            }
    3008            return list.toArray(new String[list.size()]);
    3009        }
    3010
    3011        /**
    3012         * <p>Splits a String by Character type as returned by
    3013         * <code>java.lang.Character.getType(char)</code>. Groups of contiguous
    3014         * characters of the same type are returned as complete tokens.
    3015         * <pre>
    3016         * StringUtils.splitByCharacterType(null)         = null
    3017         * StringUtils.splitByCharacterType("")           = []
    3018         * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    3019         * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    3020         * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    3021         * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
    3022         * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
    3023         * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
    3024         * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
    3025         * </pre>
    3026         * @param str the String to split, may be <code>null</code>
    3027         * @return an array of parsed Strings, <code>null</code> if null String input
    3028         * @since 2.4
    3029         */
    3030        public static String[] splitByCharacterType(String str) {
    3031            return splitByCharacterType(str, false);
    3032        }
    3033
    3034        /**
    3035         * <p>Splits a String by Character type as returned by
    3036         * <code>java.lang.Character.getType(char)</code>. Groups of contiguous
    3037         * characters of the same type are returned as complete tokens, with the
    3038         * following exception: the character of type
    3039         * <code>Character.UPPERCASE_LETTER</code>, if any, immediately
    3040         * preceding a token of type <code>Character.LOWERCASE_LETTER</code>
    3041         * will belong to the following token rather than to the preceding, if any,
    3042         * <code>Character.UPPERCASE_LETTER</code> token.
    3043         * <pre>
    3044         * StringUtils.splitByCharacterTypeCamelCase(null)         = null
    3045         * StringUtils.splitByCharacterTypeCamelCase("")           = []
    3046         * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
    3047         * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
    3048         * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
    3049         * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
    3050         * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
    3051         * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
    3052         * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
    3053         * </pre>
    3054         * @param str the String to split, may be <code>null</code>
    3055         * @return an array of parsed Strings, <code>null</code> if null String input
    3056         * @since 2.4
    3057         */
    3058        public static String[] splitByCharacterTypeCamelCase(String str) {
    3059            return splitByCharacterType(str, true);
    3060        }
    3061
    3062        /**
    3063         * <p>Splits a String by Character type as returned by
    3064         * <code>java.lang.Character.getType(char)</code>. Groups of contiguous
    3065         * characters of the same type are returned as complete tokens, with the
    3066         * following exception: if <code>camelCase</code> is <code>true</code>,
    3067         * the character of type <code>Character.UPPERCASE_LETTER</code>, if any,
    3068         * immediately preceding a token of type <code>Character.LOWERCASE_LETTER</code>
    3069         * will belong to the following token rather than to the preceding, if any,
    3070         * <code>Character.UPPERCASE_LETTER</code> token.
    3071         * @param str the String to split, may be <code>null</code>
    3072         * @param camelCase whether to use so-called "camel-case" for letter types
    3073         * @return an array of parsed Strings, <code>null</code> if null String input
    3074         * @since 2.4
    3075         */
    3076        private static String[] splitByCharacterType(String str, boolean camelCase) {
    3077            if (str == null) {
    3078                return null;
    3079            }
    3080            if (str.length() == 0) {
    3081                return ArrayUtils.EMPTY_STRING_ARRAY;
    3082            }
    3083            char[] c = str.toCharArray();
    3084            List<String> list = new ArrayList<String>();
    3085            int tokenStart = 0;
    3086            int currentType = Character.getType(c[tokenStart]);
    3087            for (int pos = tokenStart + 1; pos < c.length; pos++) {
    3088                int type = Character.getType(c[pos]);
    3089                if (type == currentType) {
    3090                    continue;
    3091                }
    3092                if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
    3093                    int newTokenStart = pos - 1;
    3094                    if (newTokenStart != tokenStart) {
    3095                        list.add(new String(c, tokenStart, newTokenStart - tokenStart));
    3096                        tokenStart = newTokenStart;
    3097                    }
    3098                } else {
    3099                    list.add(new String(c, tokenStart, pos - tokenStart));
    3100                    tokenStart = pos;
    3101                }
    3102                currentType = type;
    3103            }
    3104            list.add(new String(c, tokenStart, c.length - tokenStart));
    3105            return list.toArray(new String[list.size()]);
    3106        }
    3107
    3108        // Joining
    3109        //-----------------------------------------------------------------------
    3110        /**
    3111         * <p>Joins the provided elements into a single String. </p>
    3112         *
    3113         * <p>No separator is added to the joined String.
    3114         * Null objects or empty string elements are represented by
    3115         * empty strings.</p>
    3116         *
    3117         * <pre>
    3118         * StringUtils.concat("a", "b", "c") = "abc"
    3119         * StringUtils.concat(null, "", "a") = "a"
    3120         * </pre>
    3121         *
    3122         * @param elements  the values to join together
    3123         * @return the concatenated String
    3124         * @since 3.0
    3125         */
    3126        public static String concat(Object... elements) {
    3127            return join(elements, null);
    3128        }
    3129
    3130        /**
    3131         * <p>Joins the provided elements into a single String, with the specified
    3132         * separator between each element. </p>
    3133         *
    3134         * <p>No separator is added before or after the joined String.
    3135         * Null objects or empty string elements are represented by
    3136         * empty strings.</p>
    3137         *
    3138         * <pre>
    3139         * StringUtils.concatWith(".", "a", "b", "c") = "a.b.c"
    3140         * StringUtils.concatWith("", null, "", "a") = "a"
    3141         * </pre>
    3142         *
    3143         * @param separator the value to put between elements
    3144         * @param elements  the values to join together
    3145         * @return the concatenated String
    3146         * @since 3.0
    3147         */
    3148        public static String concatWith(String separator, Object... elements) {
    3149            return join(elements, separator);
    3150        }
    3151
    3152        /**
    3153         * <p>Joins the elements of the provided array into a single String
    3154         * containing the provided list of elements.</p>
    3155         *
    3156         * <p>No separator is added to the joined String.
    3157         * Null objects or empty strings within the array are represented by
    3158         * empty strings.</p>
    3159         *
    3160         * <pre>
    3161         * StringUtils.join(null)            = null
    3162         * StringUtils.join([])              = ""
    3163         * StringUtils.join([null])          = ""
    3164         * StringUtils.join(["a", "b", "c"]) = "abc"
    3165         * StringUtils.join([null, "", "a"]) = "a"
    3166         * </pre>
    3167         *
    3168         * @param array  the array of values to join together, may be null
    3169         * @return the joined String, <code>null</code> if null array input
    3170         * @since 2.0
    3171         */
    3172        public static String join(Object[] array) {
    3173            return join(array, null);
    3174        }
    3175
    3176        /**
    3177         * <p>Joins the elements of the provided array into a single String
    3178         * containing the provided list of elements.</p>
    3179         *
    3180         * <p>No delimiter is added before or after the list.
    3181         * Null objects or empty strings within the array are represented by
    3182         * empty strings.</p>
    3183         *
    3184         * <pre>
    3185         * StringUtils.join(null, *)               = null
    3186         * StringUtils.join([], *)                 = ""
    3187         * StringUtils.join([null], *)             = ""
    3188         * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    3189         * StringUtils.join(["a", "b", "c"], null) = "abc"
    3190         * StringUtils.join([null, "", "a"], ';')  = ";;a"
    3191         * </pre>
    3192         *
    3193         * @param array  the array of values to join together, may be null
    3194         * @param separator  the separator character to use
    3195         * @return the joined String, <code>null</code> if null array input
    3196         * @since 2.0
    3197         */
    3198        public static String join(Object[] array, char separator) {
    3199            if (array == null) {
    3200                return null;
    3201            }
    3202
    3203            return join(array, separator, 0, array.length);
    3204        }
    3205
    3206        /**
    3207         * <p>Joins the elements of the provided array into a single String
    3208         * containing the provided list of elements.</p>
    3209         *
    3210         * <p>No delimiter is added before or after the list.
    3211         * Null objects or empty strings within the array are represented by
    3212         * empty strings.</p>
    3213         *
    3214         * <pre>
    3215         * StringUtils.join(null, *)               = null
    3216         * StringUtils.join([], *)                 = ""
    3217         * StringUtils.join([null], *)             = ""
    3218         * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
    3219         * StringUtils.join(["a", "b", "c"], null) = "abc"
    3220         * StringUtils.join([null, "", "a"], ';')  = ";;a"
    3221         * </pre>
    3222         *
    3223         * @param array  the array of values to join together, may be null
    3224         * @param separator  the separator character to use
    3225         * @param startIndex the first index to start joining from.  It is
    3226         * an error to pass in an end index past the end of the array
    3227         * @param endIndex the index to stop joining from (exclusive). It is
    3228         * an error to pass in an end index past the end of the array
    3229         * @return the joined String, <code>null</code> if null array input
    3230         * @since 2.0
    3231         */
    3232        public static String join(Object[] array, char separator, int startIndex, int endIndex) {
    3233            if (array == null) {
    3234                return null;
    3235            }
    3236            int bufSize = (endIndex - startIndex);
    3237            if (bufSize <= 0) {
    3238                return EMPTY;
    3239            }
    3240
    3241            bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length()) + 1);
    3242            StringBuilder buf = new StringBuilder(bufSize);
    3243
    3244            for (int i = startIndex; i < endIndex; i++) {
    3245                if (i > startIndex) {
    3246                    buf.append(separator);
    3247                }
    3248                if (array[i] != null) {
    3249                    buf.append(array[i]);
    3250                }
    3251            }
    3252            return buf.toString();
    3253        }
    3254
    3255
    3256        /**
    3257         * <p>Joins the elements of the provided array into a single String
    3258         * containing the provided list of elements.</p>
    3259         *
    3260         * <p>No delimiter is added before or after the list.
    3261         * A <code>null</code> separator is the same as an empty String ("").
    3262         * Null objects or empty strings within the array are represented by
    3263         * empty strings.</p>
    3264         *
    3265         * <pre>
    3266         * StringUtils.join(null, *)                = null
    3267         * StringUtils.join([], *)                  = ""
    3268         * StringUtils.join([null], *)              = ""
    3269         * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    3270         * StringUtils.join(["a", "b", "c"], null)  = "abc"
    3271         * StringUtils.join(["a", "b", "c"], "")    = "abc"
    3272         * StringUtils.join([null, "", "a"], ',')   = ",,a"
    3273         * </pre>
    3274         *
    3275         * @param array  the array of values to join together, may be null
    3276         * @param separator  the separator character to use, null treated as ""
    3277         * @return the joined String, <code>null</code> if null array input
    3278         */
    3279        public static String join(Object[] array, String separator) {
    3280            if (array == null) {
    3281                return null;
    3282            }
    3283            return join(array, separator, 0, array.length);
    3284        }
    3285
    3286        /**
    3287         * <p>Joins the elements of the provided array into a single String
    3288         * containing the provided list of elements.</p>
    3289         *
    3290         * <p>No delimiter is added before or after the list.
    3291         * A <code>null</code> separator is the same as an empty String ("").
    3292         * Null objects or empty strings within the array are represented by
    3293         * empty strings.</p>
    3294         *
    3295         * <pre>
    3296         * StringUtils.join(null, *)                = null
    3297         * StringUtils.join([], *)                  = ""
    3298         * StringUtils.join([null], *)              = ""
    3299         * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
    3300         * StringUtils.join(["a", "b", "c"], null)  = "abc"
    3301         * StringUtils.join(["a", "b", "c"], "")    = "abc"
    3302         * StringUtils.join([null, "", "a"], ',')   = ",,a"
    3303         * </pre>
    3304         *
    3305         * @param array  the array of values to join together, may be null
    3306         * @param separator  the separator character to use, null treated as ""
    3307         * @param startIndex the first index to start joining from.  It is
    3308         * an error to pass in an end index past the end of the array
    3309         * @param endIndex the index to stop joining from (exclusive). It is
    3310         * an error to pass in an end index past the end of the array
    3311         * @return the joined String, <code>null</code> if null array input
    3312         */
    3313        public static String join(Object[] array, String separator, int startIndex, int endIndex) {
    3314            if (array == null) {
    3315                return null;
    3316            }
    3317            if (separator == null) {
    3318                separator = EMPTY;
    3319            }
    3320
    3321            // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
    3322            //           (Assuming that all Strings are roughly equally long)
    3323            int bufSize = (endIndex - startIndex);
    3324            if (bufSize <= 0) {
    3325                return EMPTY;
    3326            }
    3327
    3328            bufSize *= ((array[startIndex] == null ? 16 : array[startIndex].toString().length())
    3329                            + separator.length());
    3330
    3331            StringBuilder buf = new StringBuilder(bufSize);
    3332
    3333            for (int i = startIndex; i < endIndex; i++) {
    3334                if (i > startIndex) {
    3335                    buf.append(separator);
    3336                }
    3337                if (array[i] != null) {
    3338                    buf.append(array[i]);
    3339                }
    3340            }
    3341            return buf.toString();
    3342        }
    3343
    3344        /**
    3345         * <p>Joins the elements of the provided <code>Iterator</code> into
    3346         * a single String containing the provided elements.</p>
    3347         *
    3348         * <p>No delimiter is added before or after the list. Null objects or empty
    3349         * strings within the iteration are represented by empty strings.</p>
    3350         *
    3351         * <p>See the examples here: {@link #join(Object[],char)}. </p>
    3352         *
    3353         * @param iterator  the <code>Iterator</code> of values to join together, may be null
    3354         * @param separator  the separator character to use
    3355         * @return the joined String, <code>null</code> if null iterator input
    3356         * @since 2.0
    3357         */
    3358        public static String join(Iterator<?> iterator, char separator) {
    3359
    3360            // handle null, zero and one elements before building a buffer
    3361            if (iterator == null) {
    3362                return null;
    3363            }
    3364            if (!iterator.hasNext()) {
    3365                return EMPTY;
    3366            }
    3367            Object first = iterator.next();
    3368            if (!iterator.hasNext()) {
    3369                return ObjectUtils.toString(first);
    3370            }
    3371
    3372            // two or more elements
    3373            StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
    3374            if (first != null) {
    3375                buf.append(first);
    3376            }
    3377
    3378            while (iterator.hasNext()) {
    3379                buf.append(separator);
    3380                Object obj = iterator.next();
    3381                if (obj != null) {
    3382                    buf.append(obj);
    3383                }
    3384            }
    3385
    3386            return buf.toString();
    3387        }
    3388
    3389        /**
    3390         * <p>Joins the elements of the provided <code>Iterator</code> into
    3391         * a single String containing the provided elements.</p>
    3392         *
    3393         * <p>No delimiter is added before or after the list.
    3394         * A <code>null</code> separator is the same as an empty String ("").</p>
    3395         *
    3396         * <p>See the examples here: {@link #join(Object[],String)}. </p>
    3397         *
    3398         * @param iterator  the <code>Iterator</code> of values to join together, may be null
    3399         * @param separator  the separator character to use, null treated as ""
    3400         * @return the joined String, <code>null</code> if null iterator input
    3401         */
    3402        public static String join(Iterator<?> iterator, String separator) {
    3403
    3404            // handle null, zero and one elements before building a buffer
    3405            if (iterator == null) {
    3406                return null;
    3407            }
    3408            if (!iterator.hasNext()) {
    3409                return EMPTY;
    3410            }
    3411            Object first = iterator.next();
    3412            if (!iterator.hasNext()) {
    3413                return ObjectUtils.toString(first);
    3414            }
    3415
    3416            // two or more elements
    3417            StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
    3418            if (first != null) {
    3419                buf.append(first);
    3420            }
    3421
    3422            while (iterator.hasNext()) {
    3423                if (separator != null) {
    3424                    buf.append(separator);
    3425                }
    3426                Object obj = iterator.next();
    3427                if (obj != null) {
    3428                    buf.append(obj);
    3429                }
    3430            }
    3431            return buf.toString();
    3432        }
    3433
    3434        /**
    3435         * <p>Joins the elements of the provided <code>Iterable</code> into
    3436         * a single String containing the provided elements.</p>
    3437         *
    3438         * <p>No delimiter is added before or after the list. Null objects or empty
    3439         * strings within the iteration are represented by empty strings.</p>
    3440         *
    3441         * <p>See the examples here: {@link #join(Object[],char)}. </p>
    3442         *
    3443         * @param iterable  the <code>Iterable</code> providing the values to join together, may be null
    3444         * @param separator  the separator character to use
    3445         * @return the joined String, <code>null</code> if null iterator input
    3446         * @since 2.3
    3447         */
    3448        public static String join(Iterable<?> iterable, char separator) {
    3449            if (iterable == null) {
    3450                return null;
    3451            }
    3452            return join(iterable.iterator(), separator);
    3453        }
    3454
    3455        /**
    3456         * <p>Joins the elements of the provided <code>Iterable</code> into
    3457         * a single String containing the provided elements.</p>
    3458         *
    3459         * <p>No delimiter is added before or after the list.
    3460         * A <code>null</code> separator is the same as an empty String ("").</p>
    3461         *
    3462         * <p>See the examples here: {@link #join(Object[],String)}. </p>
    3463         *
    3464         * @param iterable  the <code>Iterable</code> providing the values to join together, may be null
    3465         * @param separator  the separator character to use, null treated as ""
    3466         * @return the joined String, <code>null</code> if null iterator input
    3467         * @since 2.3
    3468         */
    3469        public static String join(Iterable<?> iterable, String separator) {
    3470            if (iterable == null) {
    3471                return null;
    3472            }
    3473            return join(iterable.iterator(), separator);
    3474        }
    3475
    3476        // Delete
    3477        //-----------------------------------------------------------------------
    3478        /**
    3479         * <p>Deletes all whitespaces from a String as defined by
    3480         * {@link Character#isWhitespace(char)}.</p>
    3481         *
    3482         * <pre>
    3483         * StringUtils.deleteWhitespace(null)         = null
    3484         * StringUtils.deleteWhitespace("")           = ""
    3485         * StringUtils.deleteWhitespace("abc")        = "abc"
    3486         * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
    3487         * </pre>
    3488         *
    3489         * @param str  the String to delete whitespace from, may be null
    3490         * @return the String without whitespaces, <code>null</code> if null String input
    3491         */
    3492        public static String deleteWhitespace(String str) {
    3493            if (isEmpty(str)) {
    3494                return str;
    3495            }
    3496            int sz = str.length();
    3497            char[] chs = new char[sz];
    3498            int count = 0;
    3499            for (int i = 0; i < sz; i++) {
    3500                if (!Character.isWhitespace(str.charAt(i))) {
    3501                    chs[count++] = str.charAt(i);
    3502                }
    3503            }
    3504            if (count == sz) {
    3505                return str;
    3506            }
    3507            return new String(chs, 0, count);
    3508        }
    3509
    3510        // Remove
    3511        //-----------------------------------------------------------------------
    3512        /**
    3513         * <p>Removes a substring only if it is at the begining of a source string,
    3514         * otherwise returns the source string.</p>
    3515         *
    3516         * <p>A <code>null</code> source string will return <code>null</code>.
    3517         * An empty ("") source string will return the empty string.
    3518         * A <code>null</code> search string will return the source string.</p>
    3519         *
    3520         * <pre>
    3521         * StringUtils.removeStart(null, *)      = null
    3522         * StringUtils.removeStart("", *)        = ""
    3523         * StringUtils.removeStart(*, null)      = *
    3524         * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
    3525         * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
    3526         * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
    3527         * StringUtils.removeStart("abc", "")    = "abc"
    3528         * </pre>
    3529         *
    3530         * @param str  the source String to search, may be null
    3531         * @param remove  the String to search for and remove, may be null
    3532         * @return the substring with the string removed if found,
    3533         *  <code>null</code> if null String input
    3534         * @since 2.1
    3535         */
    3536        public static String removeStart(String str, String remove) {
    3537            if (isEmpty(str) || isEmpty(remove)) {
    3538                return str;
    3539            }
    3540            if (str.startsWith(remove)){
    3541                return str.substring(remove.length());
    3542            }
    3543            return str;
    3544        }
    3545
    3546        /**
    3547         * <p>Case insensitive removal of a substring if it is at the begining of a source string,
    3548         * otherwise returns the source string.</p>
    3549         *
    3550         * <p>A <code>null</code> source string will return <code>null</code>.
    3551         * An empty ("") source string will return the empty string.
    3552         * A <code>null</code> search string will return the source string.</p>
    3553         *
    3554         * <pre>
    3555         * StringUtils.removeStartIgnoreCase(null, *)      = null
    3556         * StringUtils.removeStartIgnoreCase("", *)        = ""
    3557         * StringUtils.removeStartIgnoreCase(*, null)      = *
    3558         * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
    3559         * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
    3560         * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
    3561         * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    3562         * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
    3563         * </pre>
    3564         *
    3565         * @param str  the source String to search, may be null
    3566         * @param remove  the String to search for (case insensitive) and remove, may be null
    3567         * @return the substring with the string removed if found,
    3568         *  <code>null</code> if null String input
    3569         * @since 2.4
    3570         */
    3571        public static String removeStartIgnoreCase(String str, String remove) {
    3572            if (isEmpty(str) || isEmpty(remove)) {
    3573                return str;
    3574            }
    3575            if (startsWithIgnoreCase(str, remove)) {
    3576                return str.substring(remove.length());
    3577            }
    3578            return str;
    3579        }
    3580
    3581        /**
    3582         * <p>Removes a substring only if it is at the end of a source string,
    3583         * otherwise returns the source string.</p>
    3584         *
    3585         * <p>A <code>null</code> source string will return <code>null</code>.
    3586         * An empty ("") source string will return the empty string.
    3587         * A <code>null</code> search string will return the source string.</p>
    3588         *
    3589         * <pre>
    3590         * StringUtils.removeEnd(null, *)      = null
    3591         * StringUtils.removeEnd("", *)        = ""
    3592         * StringUtils.removeEnd(*, null)      = *
    3593         * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
    3594         * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
    3595         * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
    3596         * StringUtils.removeEnd("abc", "")    = "abc"
    3597         * </pre>
    3598         *
    3599         * @param str  the source String to search, may be null
    3600         * @param remove  the String to search for and remove, may be null
    3601         * @return the substring with the string removed if found,
    3602         *  <code>null</code> if null String input
    3603         * @since 2.1
    3604         */
    3605        public static String removeEnd(String str, String remove) {
    3606            if (isEmpty(str) || isEmpty(remove)) {
    3607                return str;
    3608            }
    3609            if (str.endsWith(remove)) {
    3610                return str.substring(0, str.length() - remove.length());
    3611            }
    3612            return str;
    3613        }
    3614
    3615        /**
    3616         * <p>Case insensitive removal of a substring if it is at the end of a source string,
    3617         * otherwise returns the source string.</p>
    3618         *
    3619         * <p>A <code>null</code> source string will return <code>null</code>.
    3620         * An empty ("") source string will return the empty string.
    3621         * A <code>null</code> search string will return the source string.</p>
    3622         *
    3623         * <pre>
    3624         * StringUtils.removeEndIgnoreCase(null, *)      = null
    3625         * StringUtils.removeEndIgnoreCase("", *)        = ""
    3626         * StringUtils.removeEndIgnoreCase(*, null)      = *
    3627         * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
    3628         * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
    3629         * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
    3630         * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
    3631         * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
    3632         * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
    3633         * </pre>
    3634         *
    3635         * @param str  the source String to search, may be null
    3636         * @param remove  the String to search for (case insensitive) and remove, may be null
    3637         * @return the substring with the string removed if found,
    3638         *  <code>null</code> if null String input
    3639         * @since 2.4
    3640         */
    3641        public static String removeEndIgnoreCase(String str, String remove) {
    3642            if (isEmpty(str) || isEmpty(remove)) {
    3643                return str;
    3644            }
    3645            if (endsWithIgnoreCase(str, remove)) {
    3646                return str.substring(0, str.length() - remove.length());
    3647            }
    3648            return str;
    3649        }
    3650
    3651        /**
    3652         * <p>Removes all occurrences of a substring from within the source string.</p>
    3653         *
    3654         * <p>A <code>null</code> source string will return <code>null</code>.
    3655         * An empty ("") source string will return the empty string.
    3656         * A <code>null</code> remove string will return the source string.
    3657         * An empty ("") remove string will return the source string.</p>
    3658         *
    3659         * <pre>
    3660         * StringUtils.remove(null, *)        = null
    3661         * StringUtils.remove("", *)          = ""
    3662         * StringUtils.remove(*, null)        = *
    3663         * StringUtils.remove(*, "")          = *
    3664         * StringUtils.remove("queued", "ue") = "qd"
    3665         * StringUtils.remove("queued", "zz") = "queued"
    3666         * </pre>
    3667         *
    3668         * @param str  the source String to search, may be null
    3669         * @param remove  the String to search for and remove, may be null
    3670         * @return the substring with the string removed if found,
    3671         *  <code>null</code> if null String input
    3672         * @since 2.1
    3673         */
    3674        public static String remove(String str, String remove) {
    3675            if (isEmpty(str) || isEmpty(remove)) {
    3676                return str;
    3677            }
    3678            return replace(str, remove, EMPTY, -1);
    3679        }
    3680
    3681        /**
    3682         * <p>Removes all occurrences of a character from within the source string.</p>
    3683         *
    3684         * <p>A <code>null</code> source string will return <code>null</code>.
    3685         * An empty ("") source string will return the empty string.</p>
    3686         *
    3687         * <pre>
    3688         * StringUtils.remove(null, *)       = null
    3689         * StringUtils.remove("", *)         = ""
    3690         * StringUtils.remove("queued", 'u') = "qeed"
    3691         * StringUtils.remove("queued", 'z') = "queued"
    3692         * </pre>
    3693         *
    3694         * @param str  the source String to search, may be null
    3695         * @param remove  the char to search for and remove, may be null
    3696         * @return the substring with the char removed if found,
    3697         *  <code>null</code> if null String input
    3698         * @since 2.1
    3699         */
    3700        public static String remove(String str, char remove) {
    3701            if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
    3702                return str;
    3703            }
    3704            char[] chars = str.toCharArray();
    3705            int pos = 0;
    3706            for (int i = 0; i < chars.length; i++) {
    3707                if (chars[i] != remove) {
    3708                    chars[pos++] = chars[i];
    3709                }
    3710            }
    3711            return new String(chars, 0, pos);
    3712        }
    3713
    3714        // Replacing
    3715        //-----------------------------------------------------------------------
    3716        /**
    3717         * <p>Replaces a String with another String inside a larger String, once.</p>
    3718         *
    3719         * <p>A <code>null</code> reference passed to this method is a no-op.</p>
    3720         *
    3721         * <pre>
    3722         * StringUtils.replaceOnce(null, *, *)        = null
    3723         * StringUtils.replaceOnce("", *, *)          = ""
    3724         * StringUtils.replaceOnce("any", null, *)    = "any"
    3725         * StringUtils.replaceOnce("any", *, null)    = "any"
    3726         * StringUtils.replaceOnce("any", "", *)      = "any"
    3727         * StringUtils.replaceOnce("aba", "a", null)  = "aba"
    3728         * StringUtils.replaceOnce("aba", "a", "")    = "ba"
    3729         * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
    3730         * </pre>
    3731         *
    3732         * @see #replace(String text, String searchString, String replacement, int max)
    3733         * @param text  text to search and replace in, may be null
    3734         * @param searchString  the String to search for, may be null
    3735         * @param replacement  the String to replace with, may be null
    3736         * @return the text with any replacements processed,
    3737         *  <code>null</code> if null String input
    3738         */
    3739        public static String replaceOnce(String text, String searchString, String replacement) {
    3740            return replace(text, searchString, replacement, 1);
    3741        }
    3742
    3743        /**
    3744         * <p>Replaces all occurrences of a String within another String.</p>
    3745         *
    3746         * <p>A <code>null</code> reference passed to this method is a no-op.</p>
    3747         *
    3748         * <pre>
    3749         * StringUtils.replace(null, *, *)        = null
    3750         * StringUtils.replace("", *, *)          = ""
    3751         * StringUtils.replace("any", null, *)    = "any"
    3752         * StringUtils.replace("any", *, null)    = "any"
    3753         * StringUtils.replace("any", "", *)      = "any"
    3754         * StringUtils.replace("aba", "a", null)  = "aba"
    3755         * StringUtils.replace("aba", "a", "")    = "b"
    3756         * StringUtils.replace("aba", "a", "z")   = "zbz"
    3757         * </pre>
    3758         *
    3759         * @see #replace(String text, String searchString, String replacement, int max)
    3760         * @param text  text to search and replace in, may be null
    3761         * @param searchString  the String to search for, may be null
    3762         * @param replacement  the String to replace it with, may be null
    3763         * @return the text with any replacements processed,
    3764         *  <code>null</code> if null String input
    3765         */
    3766        public static String replace(String text, String searchString, String replacement) {
    3767            return replace(text, searchString, replacement, -1);
    3768        }
    3769
    3770        /**
    3771         * <p>Replaces a String with another String inside a larger String,
    3772         * for the first <code>max</code> values of the search String.</p>
    3773         *
    3774         * <p>A <code>null</code> reference passed to this method is a no-op.</p>
    3775         *
    3776         * <pre>
    3777         * StringUtils.replace(null, *, *, *)         = null
    3778         * StringUtils.replace("", *, *, *)           = ""
    3779         * StringUtils.replace("any", null, *, *)     = "any"
    3780         * StringUtils.replace("any", *, null, *)     = "any"
    3781         * StringUtils.replace("any", "", *, *)       = "any"
    3782         * StringUtils.replace("any", *, *, 0)        = "any"
    3783         * StringUtils.replace("abaa", "a", null, -1) = "abaa"
    3784         * StringUtils.replace("abaa", "a", "", -1)   = "b"
    3785         * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
    3786         * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
    3787         * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
    3788         * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
    3789         * </pre>
    3790         *
    3791         * @param text  text to search and replace in, may be null
    3792         * @param searchString  the String to search for, may be null
    3793         * @param replacement  the String to replace it with, may be null
    3794         * @param max  maximum number of values to replace, or <code>-1</code> if no maximum
    3795         * @return the text with any replacements processed,
    3796         *  <code>null</code> if null String input
    3797         */
    3798        public static String replace(String text, String searchString, String replacement, int max) {
    3799            if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
    3800                return text;
    3801            }
    3802            int start = 0;
    3803            int end = text.indexOf(searchString, start);
    3804            if (end == INDEX_NOT_FOUND) {
    3805                return text;
    3806            }
    3807            int replLength = searchString.length();
    3808            int increase = replacement.length() - replLength;
    3809            increase = (increase < 0 ? 0 : increase);
    3810            increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
    3811            StringBuilder buf = new StringBuilder(text.length() + increase);
    3812            while (end != INDEX_NOT_FOUND) {
    3813                buf.append(text.substring(start, end)).append(replacement);
    3814                start = end + replLength;
    3815                if (--max == 0) {
    3816                    break;
    3817                }
    3818                end = text.indexOf(searchString, start);
    3819            }
    3820            buf.append(text.substring(start));
    3821            return buf.toString();
    3822        }
    3823
    3824        /**
    3825         * <p>
    3826         * Replaces all occurrences of Strings within another String.
    3827         * </p>
    3828         *
    3829         * <p>
    3830         * A <code>null</code> reference passed to this method is a no-op, or if
    3831         * any "search string" or "string to replace" is null, that replace will be
    3832         * ignored. This will not repeat. For repeating replaces, call the
    3833         * overloaded method.
    3834         * </p>
    3835         *
    3836         * <pre>
    3837         *  StringUtils.replaceEach(null, *, *)        = null
    3838         *  StringUtils.replaceEach("", *, *)          = ""
    3839         *  StringUtils.replaceEach("aba", null, null) = "aba"
    3840         *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
    3841         *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
    3842         *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
    3843         *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
    3844         *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
    3845         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
    3846         *  (example of how it does not repeat)
    3847         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
    3848         * </pre>
    3849         *
    3850         * @param text
    3851         *            text to search and replace in, no-op if null
    3852         * @param searchList
    3853         *            the Strings to search for, no-op if null
    3854         * @param replacementList
    3855         *            the Strings to replace them with, no-op if null
    3856         * @return the text with any replacements processed, <code>null</code> if
    3857         *         null String input
    3858         * @throws IndexOutOfBoundsException
    3859         *             if the lengths of the arrays are not the same (null is ok,
    3860         *             and/or size 0)
    3861         * @since 2.4
    3862         */
    3863        public static String replaceEach(String text, String[] searchList, String[] replacementList) {
    3864            return replaceEach(text, searchList, replacementList, false, 0);
    3865        }
    3866
    3867        /**
    3868         * <p>
    3869         * Replaces all occurrences of Strings within another String.
    3870         * </p>
    3871         *
    3872         * <p>
    3873         * A <code>null</code> reference passed to this method is a no-op, or if
    3874         * any "search string" or "string to replace" is null, that replace will be
    3875         * ignored. This will not repeat. For repeating replaces, call the
    3876         * overloaded method.
    3877         * </p>
    3878         *
    3879         * <pre>
    3880         *  StringUtils.replaceEach(null, *, *, *) = null
    3881         *  StringUtils.replaceEach("", *, *, *) = ""
    3882         *  StringUtils.replaceEach("aba", null, null, *) = "aba"
    3883         *  StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
    3884         *  StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
    3885         *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
    3886         *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
    3887         *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
    3888         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
    3889         *  (example of how it repeats)
    3890         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
    3891         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
    3892         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, true) = IllegalArgumentException
    3893         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, false) = "dcabe"
    3894         * </pre>
    3895         *
    3896         * @param text
    3897         *            text to search and replace in, no-op if null
    3898         * @param searchList
    3899         *            the Strings to search for, no-op if null
    3900         * @param replacementList
    3901         *            the Strings to replace them with, no-op if null
    3902         * @return the text with any replacements processed, <code>null</code> if
    3903         *         null String input
    3904         * @throws IllegalArgumentException
    3905         *             if the search is repeating and there is an endless loop due
    3906         *             to outputs of one being inputs to another
    3907         * @throws IndexOutOfBoundsException
    3908         *             if the lengths of the arrays are not the same (null is ok,
    3909         *             and/or size 0)
    3910         * @since 2.4
    3911         */
    3912        public static String replaceEachRepeatedly(String text, String[] searchList, String[] replacementList) {
    3913            // timeToLive should be 0 if not used or nothing to replace, else it's
    3914            // the length of the replace array
    3915            int timeToLive = searchList == null ? 0 : searchList.length;
    3916            return replaceEach(text, searchList, replacementList, true, timeToLive);
    3917        }
    3918
    3919        /**
    3920         * <p>
    3921         * Replaces all occurrences of Strings within another String.
    3922         * </p>
    3923         *
    3924         * <p>
    3925         * A <code>null</code> reference passed to this method is a no-op, or if
    3926         * any "search string" or "string to replace" is null, that replace will be
    3927         * ignored.
    3928         * </p>
    3929         *
    3930         * <pre>
    3931         *  StringUtils.replaceEach(null, *, *, *) = null
    3932         *  StringUtils.replaceEach("", *, *, *) = ""
    3933         *  StringUtils.replaceEach("aba", null, null, *) = "aba"
    3934         *  StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
    3935         *  StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
    3936         *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
    3937         *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
    3938         *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
    3939         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
    3940         *  (example of how it repeats)
    3941         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
    3942         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
    3943         *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalArgumentException
    3944         * </pre>
    3945         *
    3946         * @param text
    3947         *            text to search and replace in, no-op if null
    3948         * @param searchList
    3949         *            the Strings to search for, no-op if null
    3950         * @param replacementList
    3951         *            the Strings to replace them with, no-op if null
    3952         * @param repeat if true, then replace repeatedly
    3953         *       until there are no more possible replacements or timeToLive < 0
    3954         * @param timeToLive
    3955         *            if less than 0 then there is a circular reference and endless
    3956         *            loop
    3957         * @return the text with any replacements processed, <code>null</code> if
    3958         *         null String input
    3959         * @throws IllegalArgumentException
    3960         *             if the search is repeating and there is an endless loop due
    3961         *             to outputs of one being inputs to another
    3962         * @throws IndexOutOfBoundsException
    3963         *             if the lengths of the arrays are not the same (null is ok,
    3964         *             and/or size 0)
    3965         * @since 2.4
    3966         */
    3967        private static String replaceEach(String text, String[] searchList, String[] replacementList,
    3968                                          boolean repeat, int timeToLive)
    3969        {
    3970
    3971            // mchyzer Performance note: This creates very few new objects (one major goal)
    3972            // let me know if there are performance requests, we can create a harness to measure
    3973
    3974            if (text == null || text.length() == 0 || searchList == null ||
    3975                searchList.length == 0 || replacementList == null || replacementList.length == 0)
    3976            {
    3977                return text;
    3978            }
    3979
    3980            // if recursing, this shouldnt be less than 0
    3981            if (timeToLive < 0) {
    3982                throw new IllegalStateException("TimeToLive of " + timeToLive + " is less than 0: " + text);
    3983            }
    3984
    3985            int searchLength = searchList.length;
    3986            int replacementLength = replacementList.length;
    3987
    3988            // make sure lengths are ok, these need to be equal
    3989            if (searchLength != replacementLength) {
    3990                throw new IllegalArgumentException("Search and Replace array lengths don't match: "
    3991                    + searchLength
    3992                    + " vs "
    3993                    + replacementLength);
    3994            }
    3995
    3996            // keep track of which still have matches
    3997            boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
    3998
    3999            // index on index that the match was found
    4000            int textIndex = -1;
    4001            int replaceIndex = -1;
    4002            int tempIndex = -1;
    4003
    4004            // index of replace array that will replace the search string found
    4005            // NOTE: logic duplicated below START
    4006            for (int i = 0; i < searchLength; i++) {
    4007                if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
    4008                    searchList[i].length() == 0 || replacementList[i] == null)
    4009                {
    4010                    continue;
    4011                }
    4012                tempIndex = text.indexOf(searchList[i]);
    4013
    4014                // see if we need to keep searching for this
    4015                if (tempIndex == -1) {
    4016                    noMoreMatchesForReplIndex[i] = true;
    4017                } else {
    4018                    if (textIndex == -1 || tempIndex < textIndex) {
    4019                        textIndex = tempIndex;
    4020                        replaceIndex = i;
    4021                    }
    4022                }
    4023            }
    4024            // NOTE: logic mostly below END
    4025
    4026            // no search strings found, we are done
    4027            if (textIndex == -1) {
    4028                return text;
    4029            }
    4030
    4031            int start = 0;
    4032
    4033            // get a good guess on the size of the result buffer so it doesnt have to double if it goes over a bit
    4034            int increase = 0;
    4035
    4036            // count the replacement text elements that are larger than their corresponding text being replaced
    4037            for (int i = 0; i < searchList.length; i++) {
    4038                if (searchList[i] == null || replacementList[i] == null) {
    4039                    continue;
    4040                }
    4041                int greater = replacementList[i].length() - searchList[i].length();
    4042                if (greater > 0) {
    4043                    increase += 3 * greater; // assume 3 matches
    4044                }
    4045            }
    4046            // have upper-bound at 20% increase, then let Java take over
    4047            increase = Math.min(increase, text.length() / 5);
    4048
    4049            StringBuilder buf = new StringBuilder(text.length() + increase);
    4050
    4051            while (textIndex != -1) {
    4052
    4053                for (int i = start; i < textIndex; i++) {
    4054                    buf.append(text.charAt(i));
    4055                }
    4056                buf.append(replacementList[replaceIndex]);
    4057
    4058                start = textIndex + searchList[replaceIndex].length();
    4059
    4060                textIndex = -1;
    4061                replaceIndex = -1;
    4062                tempIndex = -1;
    4063                // find the next earliest match
    4064                // NOTE: logic mostly duplicated above START
    4065                for (int i = 0; i < searchLength; i++) {
    4066                    if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
    4067                        searchList[i].length() == 0 || replacementList[i] == null)
    4068                    {
    4069                        continue;
    4070                    }
    4071                    tempIndex = text.indexOf(searchList[i], start);
    4072
    4073                    // see if we need to keep searching for this
    4074                    if (tempIndex == -1) {
    4075                        noMoreMatchesForReplIndex[i] = true;
    4076                    } else {
    4077                        if (textIndex == -1 || tempIndex < textIndex) {
    4078                            textIndex = tempIndex;
    4079                            replaceIndex = i;
    4080                        }
    4081                    }
    4082                }
    4083                // NOTE: logic duplicated above END
    4084
    4085            }
    4086            int textLength = text.length();
    4087            for (int i = start; i < textLength; i++) {
    4088                buf.append(text.charAt(i));
    4089            }
    4090            String result = buf.toString();
    4091            if (!repeat) {
    4092                return result;
    4093            }
    4094
    4095            return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
    4096        }
    4097
    4098        // Replace, character based
    4099        //-----------------------------------------------------------------------
    4100        /**
    4101         * <p>Replaces all occurrences of a character in a String with another.
    4102         * This is a null-safe version of {@link String#replace(char, char)}.</p>
    4103         *
    4104         * <p>A <code>null</code> string input returns <code>null</code>.
    4105         * An empty ("") string input returns an empty string.</p>
    4106         *
    4107         * <pre>
    4108         * StringUtils.replaceChars(null, *, *)        = null
    4109         * StringUtils.replaceChars("", *, *)          = ""
    4110         * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
    4111         * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
    4112         * </pre>
    4113         *
    4114         * @param str  String to replace characters in, may be null
    4115         * @param searchChar  the character to search for, may be null
    4116         * @param replaceChar  the character to replace, may be null
    4117         * @return modified String, <code>null</code> if null string input
    4118         * @since 2.0
    4119         */
    4120        public static String replaceChars(String str, char searchChar, char replaceChar) {
    4121            if (str == null) {
    4122                return null;
    4123            }
    4124            return str.replace(searchChar, replaceChar);
    4125        }
    4126
    4127        /**
    4128         * <p>Replaces multiple characters in a String in one go.
    4129         * This method can also be used to delete characters.</p>
    4130         *
    4131         * <p>For example:<br />
    4132         * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
    4133         *
    4134         * <p>A <code>null</code> string input returns <code>null</code>.
    4135         * An empty ("") string input returns an empty string.
    4136         * A null or empty set of search characters returns the input string.</p>
    4137         *
    4138         * <p>The length of the search characters should normally equal the length
    4139         * of the replace characters.
    4140         * If the search characters is longer, then the extra search characters
    4141         * are deleted.
    4142         * If the search characters is shorter, then the extra replace characters
    4143         * are ignored.</p>
    4144         *
    4145         * <pre>
    4146         * StringUtils.replaceChars(null, *, *)           = null
    4147         * StringUtils.replaceChars("", *, *)             = ""
    4148         * StringUtils.replaceChars("abc", null, *)       = "abc"
    4149         * StringUtils.replaceChars("abc", "", *)         = "abc"
    4150         * StringUtils.replaceChars("abc", "b", null)     = "ac"
    4151         * StringUtils.replaceChars("abc", "b", "")       = "ac"
    4152         * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
    4153         * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
    4154         * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
    4155         * </pre>
    4156         *
    4157         * @param str  String to replace characters in, may be null
    4158         * @param searchChars  a set of characters to search for, may be null
    4159         * @param replaceChars  a set of characters to replace, may be null
    4160         * @return modified String, <code>null</code> if null string input
    4161         * @since 2.0
    4162         */
    4163        public static String replaceChars(String str, String searchChars, String replaceChars) {
    4164            if (isEmpty(str) || isEmpty(searchChars)) {
    4165                return str;
    4166            }
    4167            if (replaceChars == null) {
    4168                replaceChars = EMPTY;
    4169            }
    4170            boolean modified = false;
    4171            int replaceCharsLength = replaceChars.length();
    4172            int strLength = str.length();
    4173            StringBuilder buf = new StringBuilder(strLength);
    4174            for (int i = 0; i < strLength; i++) {
    4175                char ch = str.charAt(i);
    4176                int index = searchChars.indexOf(ch);
    4177                if (index >= 0) {
    4178                    modified = true;
    4179                    if (index < replaceCharsLength) {
    4180                        buf.append(replaceChars.charAt(index));
    4181                    }
    4182                } else {
    4183                    buf.append(ch);
    4184                }
    4185            }
    4186            if (modified) {
    4187                return buf.toString();
    4188            }
    4189            return str;
    4190        }
    4191
    4192        // Overlay
    4193        //-----------------------------------------------------------------------
    4194        /**
    4195         * <p>Overlays part of a String with another String.</p>
    4196         *
    4197         * <p>A <code>null</code> string input returns <code>null</code>.
    4198         * A negative index is treated as zero.
    4199         * An index greater than the string length is treated as the string length.
    4200         * The start index is always the smaller of the two indices.</p>
    4201         *
    4202         * <pre>
    4203         * StringUtils.overlay(null, *, *, *)            = null
    4204         * StringUtils.overlay("", "abc", 0, 0)          = "abc"
    4205         * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
    4206         * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
    4207         * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
    4208         * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
    4209         * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
    4210         * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
    4211         * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
    4212         * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
    4213         * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
    4214         * </pre>
    4215         *
    4216         * @param str  the String to do overlaying in, may be null
    4217         * @param overlay  the String to overlay, may be null
    4218         * @param start  the position to start overlaying at
    4219         * @param end  the position to stop overlaying before
    4220         * @return overlayed String, <code>null</code> if null String input
    4221         * @since 2.0
    4222         */
    4223        public static String overlay(String str, String overlay, int start, int end) {
    4224            if (str == null) {
    4225                return null;
    4226            }
    4227            if (overlay == null) {
    4228                overlay = EMPTY;
    4229            }
    4230            int len = str.length();
    4231            if (start < 0) {
    4232                start = 0;
    4233            }
    4234            if (start > len) {
    4235                start = len;
    4236            }
    4237            if (end < 0) {
    4238                end = 0;
    4239            }
    4240            if (end > len) {
    4241                end = len;
    4242            }
    4243            if (start > end) {
    4244                int temp = start;
    4245                start = end;
    4246                end = temp;
    4247            }
    4248            return new StringBuilder(len + start - end + overlay.length() + 1)
    4249                .append(str.substring(0, start))
    4250                .append(overlay)
    4251                .append(str.substring(end))
    4252                .toString();
    4253        }
    4254
    4255        // Chomping
    4256        //-----------------------------------------------------------------------
    4257        /**
    4258         * <p>Removes one newline from end of a String if it's there,
    4259         * otherwise leave it alone.  A newline is &quot;<code>\n</code>&quot;,
    4260         * &quot;<code>\r</code>&quot;, or &quot;<code>\r\n</code>&quot;.</p>
    4261         *
    4262         * <p>NOTE: This method changed in 2.0.
    4263         * It now more closely matches Perl chomp.</p>
    4264         *
    4265         * <pre>
    4266         * StringUtils.chomp(null)          = null
    4267         * StringUtils.chomp("")            = ""
    4268         * StringUtils.chomp("abc \r")      = "abc "
    4269         * StringUtils.chomp("abc\n")       = "abc"
    4270         * StringUtils.chomp("abc\r\n")     = "abc"
    4271         * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
    4272         * StringUtils.chomp("abc\n\r")     = "abc\n"
    4273         * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
    4274         * StringUtils.chomp("\r")          = ""
    4275         * StringUtils.chomp("\n")          = ""
    4276         * StringUtils.chomp("\r\n")        = ""
    4277         * </pre>
    4278         *
    4279         * @param str  the String to chomp a newline from, may be null
    4280         * @return String without newline, <code>null</code> if null String input
    4281         */
    4282        public static String chomp(String str) {
    4283            if (isEmpty(str)) {
    4284                return str;
    4285            }
    4286
    4287            if (str.length() == 1) {
    4288                char ch = str.charAt(0);
    4289                if (ch == CharUtils.CR || ch == CharUtils.LF) {
    4290                    return EMPTY;
    4291                }
    4292                return str;
    4293            }
    4294
    4295            int lastIdx = str.length() - 1;
    4296            char last = str.charAt(lastIdx);
    4297
    4298            if (last == CharUtils.LF) {
    4299                if (str.charAt(lastIdx - 1) == CharUtils.CR) {
    4300                    lastIdx--;
    4301                }
    4302            } else if (last != CharUtils.CR) {
    4303                lastIdx++;
    4304            }
    4305            return str.substring(0, lastIdx);
    4306        }
    4307
    4308        /**
    4309         * <p>Removes <code>separator</code> from the end of
    4310         * <code>str</code> if it's there, otherwise leave it alone.</p>
    4311         *
    4312         * <p>NOTE: This method changed in version 2.0.
    4313         * It now more closely matches Perl chomp.
    4314         * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
    4315         * This method uses {@link String#endsWith(String)}.</p>
    4316         *
    4317         * <pre>
    4318         * StringUtils.chomp(null, *)         = null
    4319         * StringUtils.chomp("", *)           = ""
    4320         * StringUtils.chomp("foobar", "bar") = "foo"
    4321         * StringUtils.chomp("foobar", "baz") = "foobar"
    4322         * StringUtils.chomp("foo", "foo")    = ""
    4323         * StringUtils.chomp("foo ", "foo")   = "foo "
    4324         * StringUtils.chomp(" foo", "foo")   = " "
    4325         * StringUtils.chomp("foo", "foooo")  = "foo"
    4326         * StringUtils.chomp("foo", "")       = "foo"
    4327         * StringUtils.chomp("foo", null)     = "foo"
    4328         * </pre>
    4329         *
    4330         * @param str  the String to chomp from, may be null
    4331         * @param separator  separator String, may be null
    4332         * @return String without trailing separator, <code>null</code> if null String input
    4333         */
    4334        public static String chomp(String str, String separator) {
    4335            if (isEmpty(str) || separator == null) {
    4336                return str;
    4337            }
    4338            if (str.endsWith(separator)) {
    4339                return str.substring(0, str.length() - separator.length());
    4340            }
    4341            return str;
    4342        }
    4343
    4344        // Chopping
    4345        //-----------------------------------------------------------------------
    4346        /**
    4347         * <p>Remove the last character from a String.</p>
    4348         *
    4349         * <p>If the String ends in <code>\r\n</code>, then remove both
    4350         * of them.</p>
    4351         *
    4352         * <pre>
    4353         * StringUtils.chop(null)          = null
    4354         * StringUtils.chop("")            = ""
    4355         * StringUtils.chop("abc \r")      = "abc "
    4356         * StringUtils.chop("abc\n")       = "abc"
    4357         * StringUtils.chop("abc\r\n")     = "abc"
    4358         * StringUtils.chop("abc")         = "ab"
    4359         * StringUtils.chop("abc\nabc")    = "abc\nab"
    4360         * StringUtils.chop("a")           = ""
    4361         * StringUtils.chop("\r")          = ""
    4362         * StringUtils.chop("\n")          = ""
    4363         * StringUtils.chop("\r\n")        = ""
    4364         * </pre>
    4365         *
    4366         * @param str  the String to chop last character from, may be null
    4367         * @return String without last character, <code>null</code> if null String input
    4368         */
    4369        public static String chop(String str) {
    4370            if (str == null) {
    4371                return null;
    4372            }
    4373            int strLen = str.length();
    4374            if (strLen < 2) {
    4375                return EMPTY;
    4376            }
    4377            int lastIdx = strLen - 1;
    4378            String ret = str.substring(0, lastIdx);
    4379            char last = str.charAt(lastIdx);
    4380            if (last == CharUtils.LF) {
    4381                if (ret.charAt(lastIdx - 1) == CharUtils.CR) {
    4382                    return ret.substring(0, lastIdx - 1);
    4383                }
    4384            }
    4385            return ret;
    4386        }
    4387
    4388        // Conversion
    4389        //-----------------------------------------------------------------------
    4390
    4391        // Padding
    4392        //-----------------------------------------------------------------------
    4393        /**
    4394         * <p>Repeat a String <code>repeat</code> times to form a
    4395         * new String.</p>
    4396         *
    4397         * <pre>
    4398         * StringUtils.repeat(null, 2) = null
    4399         * StringUtils.repeat("", 0)   = ""
    4400         * StringUtils.repeat("", 2)   = ""
    4401         * StringUtils.repeat("a", 3)  = "aaa"
    4402         * StringUtils.repeat("ab", 2) = "abab"
    4403         * StringUtils.repeat("a", -2) = ""
    4404         * </pre>
    4405         *
    4406         * @param str  the String to repeat, may be null
    4407         * @param repeat  number of times to repeat str, negative treated as zero
    4408         * @return a new String consisting of the original String repeated,
    4409         *  <code>null</code> if null String input
    4410         */
    4411        public static String repeat(String str, int repeat) {
    4412            // Performance tuned for 2.0 (JDK1.4)
    4413
    4414            if (str == null) {
    4415                return null;
    4416            }
    4417            if (repeat <= 0) {
    4418                return EMPTY;
    4419            }
    4420            int inputLength = str.length();
    4421            if (repeat == 1 || inputLength == 0) {
    4422                return str;
    4423            }
    4424            if (inputLength == 1 && repeat <= PAD_LIMIT) {
    4425                return padding(repeat, str.charAt(0));
    4426            }
    4427
    4428            int outputLength = inputLength * repeat;
    4429            switch (inputLength) {
    4430                case 1 :
    4431                    char ch = str.charAt(0);
    4432                    char[] output1 = new char[outputLength];
    4433                    for (int i = repeat - 1; i >= 0; i--) {
    4434                        output1[i] = ch;
    4435                    }
    4436                    return new String(output1);
    4437                case 2 :
    4438                    char ch0 = str.charAt(0);
    4439                    char ch1 = str.charAt(1);
    4440                    char[] output2 = new char[outputLength];
    4441                    for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
    4442                        output2[i] = ch0;
    4443                        output2[i + 1] = ch1;
    4444                    }
    4445                    return new String(output2);
    4446                default :
    4447                    StringBuilder buf = new StringBuilder(outputLength);
    4448                    for (int i = 0; i < repeat; i++) {
    4449                        buf.append(str);
    4450                    }
    4451                    return buf.toString();
    4452            }
    4453        }
    4454
    4455        /**
    4456         * <p>Repeat a String <code>repeat</code> times to form a
    4457         * new String, with a String separator injected each time. </p>
    4458         *
    4459         * <pre>
    4460         * StringUtils.repeat(null, null, 2) = null
    4461         * StringUtils.repeat(null, "x", 2)  = null
    4462         * StringUtils.repeat("", null, 0)   = ""
    4463         * StringUtils.repeat("", "", 2)     = ""
    4464         * StringUtils.repeat("", "x", 3)    = "xxx"
    4465         * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
    4466         * </pre>
    4467         *
    4468         * @param str        the String to repeat, may be null
    4469         * @param separator  the String to inject, may be null
    4470         * @param repeat     number of times to repeat str, negative treated as zero
    4471         * @return a new String consisting of the original String repeated,
    4472         *  <code>null</code> if null String input
    4473         * @since 2.5
    4474         */
    4475        public static String repeat(String str, String separator, int repeat) {
    4476            if(str == null || separator == null) {
    4477                return repeat(str, repeat);
    4478            } else {
    4479                // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
    4480                String result = repeat(str + separator, repeat);
    4481                return removeEnd(result, separator);
    4482            }
    4483        }
    4484
    4485        /**
    4486         * <p>Returns padding using the specified delimiter repeated
    4487         * to a given length.</p>
    4488         *
    4489         * <pre>
    4490         * StringUtils.padding(0, 'e')  = ""
    4491         * StringUtils.padding(3, 'e')  = "eee"
    4492         * StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
    4493         * </pre>
    4494         *
    4495         * <p>Note: this method doesn't not support padding with
    4496         * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
    4497         * as they require a pair of <code>char</code>s to be represented.
    4498         * If you are needing to support full I18N of your applications
    4499         * consider using {@link #repeat(String, int)} instead.
    4500         * </p>
    4501         *
    4502         * @param repeat  number of times to repeat delim
    4503         * @param padChar  character to repeat
    4504         * @return String with repeated character
    4505         * @throws IndexOutOfBoundsException if <code>repeat &lt; 0</code>
    4506         * @see #repeat(String, int)
    4507         */
    4508        private static String padding(int repeat, char padChar) throws IndexOutOfBoundsException {
    4509            if (repeat < 0) {
    4510                throw new IndexOutOfBoundsException("Cannot pad a negative amount: " + repeat);
    4511            }
    4512            final char[] buf = new char[repeat];
    4513            for (int i = 0; i < buf.length; i++) {
    4514                buf[i] = padChar;
    4515            }
    4516            return new String(buf);
    4517        }
    4518
    4519        /**
    4520         * <p>Right pad a String with spaces (' ').</p>
    4521         *
    4522         * <p>The String is padded to the size of <code>size</code>.</p>
    4523         *
    4524         * <pre>
    4525         * StringUtils.rightPad(null, *)   = null
    4526         * StringUtils.rightPad("", 3)     = "   "
    4527         * StringUtils.rightPad("bat", 3)  = "bat"
    4528         * StringUtils.rightPad("bat", 5)  = "bat  "
    4529         * StringUtils.rightPad("bat", 1)  = "bat"
    4530         * StringUtils.rightPad("bat", -1) = "bat"
    4531         * </pre>
    4532         *
    4533         * @param str  the String to pad out, may be null
    4534         * @param size  the size to pad to
    4535         * @return right padded String or original String if no padding is necessary,
    4536         *  <code>null</code> if null String input
    4537         */
    4538        public static String rightPad(String str, int size) {
    4539            return rightPad(str, size, ' ');
    4540        }
    4541
    4542        /**
    4543         * <p>Right pad a String with a specified character.</p>
    4544         *
    4545         * <p>The String is padded to the size of <code>size</code>.</p>
    4546         *
    4547         * <pre>
    4548         * StringUtils.rightPad(null, *, *)     = null
    4549         * StringUtils.rightPad("", 3, 'z')     = "zzz"
    4550         * StringUtils.rightPad("bat", 3, 'z')  = "bat"
    4551         * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
    4552         * StringUtils.rightPad("bat", 1, 'z')  = "bat"
    4553         * StringUtils.rightPad("bat", -1, 'z') = "bat"
    4554         * </pre>
    4555         *
    4556         * @param str  the String to pad out, may be null
    4557         * @param size  the size to pad to
    4558         * @param padChar  the character to pad with
    4559         * @return right padded String or original String if no padding is necessary,
    4560         *  <code>null</code> if null String input
    4561         * @since 2.0
    4562         */
    4563        public static String rightPad(String str, int size, char padChar) {
    4564            if (str == null) {
    4565                return null;
    4566            }
    4567            int pads = size - str.length();
    4568            if (pads <= 0) {
    4569                return str; // returns original String when possible
    4570            }
    4571            if (pads > PAD_LIMIT) {
    4572                return rightPad(str, size, String.valueOf(padChar));
    4573            }
    4574            return str.concat(padding(pads, padChar));
    4575        }
    4576
    4577        /**
    4578         * <p>Right pad a String with a specified String.</p>
    4579         *
    4580         * <p>The String is padded to the size of <code>size</code>.</p>
    4581         *
    4582         * <pre>
    4583         * StringUtils.rightPad(null, *, *)      = null
    4584         * StringUtils.rightPad("", 3, "z")      = "zzz"
    4585         * StringUtils.rightPad("bat", 3, "yz")  = "bat"
    4586         * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
    4587         * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
    4588         * StringUtils.rightPad("bat", 1, "yz")  = "bat"
    4589         * StringUtils.rightPad("bat", -1, "yz") = "bat"
    4590         * StringUtils.rightPad("bat", 5, null)  = "bat  "
    4591         * StringUtils.rightPad("bat", 5, "")    = "bat  "
    4592         * </pre>
    4593         *
    4594         * @param str  the String to pad out, may be null
    4595         * @param size  the size to pad to
    4596         * @param padStr  the String to pad with, null or empty treated as single space
    4597         * @return right padded String or original String if no padding is necessary,
    4598         *  <code>null</code> if null String input
    4599         */
    4600        public static String rightPad(String str, int size, String padStr) {
    4601            if (str == null) {
    4602                return null;
    4603            }
    4604            if (isEmpty(padStr)) {
    4605                padStr = " ";
    4606            }
    4607            int padLen = padStr.length();
    4608            int strLen = str.length();
    4609            int pads = size - strLen;
    4610            if (pads <= 0) {
    4611                return str; // returns original String when possible
    4612            }
    4613            if (padLen == 1 && pads <= PAD_LIMIT) {
    4614                return rightPad(str, size, padStr.charAt(0));
    4615            }
    4616
    4617            if (pads == padLen) {
    4618                return str.concat(padStr);
    4619            } else if (pads < padLen) {
    4620                return str.concat(padStr.substring(0, pads));
    4621            } else {
    4622                char[] padding = new char[pads];
    4623                char[] padChars = padStr.toCharArray();
    4624                for (int i = 0; i < pads; i++) {
    4625                    padding[i] = padChars[i % padLen];
    4626                }
    4627                return str.concat(new String(padding));
    4628            }
    4629        }
    4630
    4631        /**
    4632         * <p>Left pad a String with spaces (' ').</p>
    4633         *
    4634         * <p>The String is padded to the size of <code>size</code>.</p>
    4635         *
    4636         * <pre>
    4637         * StringUtils.leftPad(null, *)   = null
    4638         * StringUtils.leftPad("", 3)     = "   "
    4639         * StringUtils.leftPad("bat", 3)  = "bat"
    4640         * StringUtils.leftPad("bat", 5)  = "  bat"
    4641         * StringUtils.leftPad("bat", 1)  = "bat"
    4642         * StringUtils.leftPad("bat", -1) = "bat"
    4643         * </pre>
    4644         *
    4645         * @param str  the String to pad out, may be null
    4646         * @param size  the size to pad to
    4647         * @return left padded String or original String if no padding is necessary,
    4648         *  <code>null</code> if null String input
    4649         */
    4650        public static String leftPad(String str, int size) {
    4651            return leftPad(str, size, ' ');
    4652        }
    4653
    4654        /**
    4655         * <p>Left pad a String with a specified character.</p>
    4656         *
    4657         * <p>Pad to a size of <code>size</code>.</p>
    4658         *
    4659         * <pre>
    4660         * StringUtils.leftPad(null, *, *)     = null
    4661         * StringUtils.leftPad("", 3, 'z')     = "zzz"
    4662         * StringUtils.leftPad("bat", 3, 'z')  = "bat"
    4663         * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
    4664         * StringUtils.leftPad("bat", 1, 'z')  = "bat"
    4665         * StringUtils.leftPad("bat", -1, 'z') = "bat"
    4666         * </pre>
    4667         *
    4668         * @param str  the String to pad out, may be null
    4669         * @param size  the size to pad to
    4670         * @param padChar  the character to pad with
    4671         * @return left padded String or original String if no padding is necessary,
    4672         *  <code>null</code> if null String input
    4673         * @since 2.0
    4674         */
    4675        public static String leftPad(String str, int size, char padChar) {
    4676            if (str == null) {
    4677                return null;
    4678            }
    4679            int pads = size - str.length();
    4680            if (pads <= 0) {
    4681                return str; // returns original String when possible
    4682            }
    4683            if (pads > PAD_LIMIT) {
    4684                return leftPad(str, size, String.valueOf(padChar));
    4685            }
    4686            return padding(pads, padChar).concat(str);
    4687        }
    4688
    4689        /**
    4690         * <p>Left pad a String with a specified String.</p>
    4691         *
    4692         * <p>Pad to a size of <code>size</code>.</p>
    4693         *
    4694         * <pre>
    4695         * StringUtils.leftPad(null, *, *)      = null
    4696         * StringUtils.leftPad("", 3, "z")      = "zzz"
    4697         * StringUtils.leftPad("bat", 3, "yz")  = "bat"
    4698         * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
    4699         * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
    4700         * StringUtils.leftPad("bat", 1, "yz")  = "bat"
    4701         * StringUtils.leftPad("bat", -1, "yz") = "bat"
    4702         * StringUtils.leftPad("bat", 5, null)  = "  bat"
    4703         * StringUtils.leftPad("bat", 5, "")    = "  bat"
    4704         * </pre>
    4705         *
    4706         * @param str  the String to pad out, may be null
    4707         * @param size  the size to pad to
    4708         * @param padStr  the String to pad with, null or empty treated as single space
    4709         * @return left padded String or original String if no padding is necessary,
    4710         *  <code>null</code> if null String input
    4711         */
    4712        public static String leftPad(String str, int size, String padStr) {
    4713            if (str == null) {
    4714                return null;
    4715            }
    4716            if (isEmpty(padStr)) {
    4717                padStr = " ";
    4718            }
    4719            int padLen = padStr.length();
    4720            int strLen = str.length();
    4721            int pads = size - strLen;
    4722            if (pads <= 0) {
    4723                return str; // returns original String when possible
    4724            }
    4725            if (padLen == 1 && pads <= PAD_LIMIT) {
    4726                return leftPad(str, size, padStr.charAt(0));
    4727            }
    4728
    4729            if (pads == padLen) {
    4730                return padStr.concat(str);
    4731            } else if (pads < padLen) {
    4732                return padStr.substring(0, pads).concat(str);
    4733            } else {
    4734                char[] padding = new char[pads];
    4735                char[] padChars = padStr.toCharArray();
    4736                for (int i = 0; i < pads; i++) {
    4737                    padding[i] = padChars[i % padLen];
    4738                }
    4739                return new String(padding).concat(str);
    4740            }
    4741        }
    4742
    4743        /**
    4744         * Gets a CharSequence length or <code>0</code> if the CharSequence is
    4745         * <code>null</code>.
    4746         *
    4747         * @param cs
    4748         *            a CharSequence or <code>null</code>
    4749         * @return CharSequence length or <code>0</code> if the CharSequence is
    4750         *         <code>null</code>.
    4751         * @since 2.4
    4752         * @deprecated See {@link CharSequenceUtils#length(CharSequence)}
    4753         * @since 3.0 Changed signature from length(String) to length(CharSequence)
    4754         */
    4755        @Deprecated
    4756        public static int length(CharSequence cs) {
    4757            return CharSequenceUtils.length(cs);
    4758        }
    4759
    4760        // Centering
    4761        //-----------------------------------------------------------------------
    4762        /**
    4763         * <p>Centers a String in a larger String of size <code>size</code>
    4764         * using the space character (' ').<p>
    4765         *
    4766         * <p>If the size is less than the String length, the String is returned.
    4767         * A <code>null</code> String returns <code>null</code>.
    4768         * A negative size is treated as zero.</p>
    4769         *
    4770         * <p>Equivalent to <code>center(str, size, " ")</code>.</p>
    4771         *
    4772         * <pre>
    4773         * StringUtils.center(null, *)   = null
    4774         * StringUtils.center("", 4)     = "    "
    4775         * StringUtils.center("ab", -1)  = "ab"
    4776         * StringUtils.center("ab", 4)   = " ab "
    4777         * StringUtils.center("abcd", 2) = "abcd"
    4778         * StringUtils.center("a", 4)    = " a  "
    4779         * </pre>
    4780         *
    4781         * @param str  the String to center, may be null
    4782         * @param size  the int size of new String, negative treated as zero
    4783         * @return centered String, <code>null</code> if null String input
    4784         */
    4785        public static String center(String str, int size) {
    4786            return center(str, size, ' ');
    4787        }
    4788
    4789        /**
    4790         * <p>Centers a String in a larger String of size <code>size</code>.
    4791         * Uses a supplied character as the value to pad the String with.</p>
    4792         *
    4793         * <p>If the size is less than the String length, the String is returned.
    4794         * A <code>null</code> String returns <code>null</code>.
    4795         * A negative size is treated as zero.</p>
    4796         *
    4797         * <pre>
    4798         * StringUtils.center(null, *, *)     = null
    4799         * StringUtils.center("", 4, ' ')     = "    "
    4800         * StringUtils.center("ab", -1, ' ')  = "ab"
    4801         * StringUtils.center("ab", 4, ' ')   = " ab"
    4802         * StringUtils.center("abcd", 2, ' ') = "abcd"
    4803         * StringUtils.center("a", 4, ' ')    = " a  "
    4804         * StringUtils.center("a", 4, 'y')    = "yayy"
    4805         * </pre>
    4806         *
    4807         * @param str  the String to center, may be null
    4808         * @param size  the int size of new String, negative treated as zero
    4809         * @param padChar  the character to pad the new String with
    4810         * @return centered String, <code>null</code> if null String input
    4811         * @since 2.0
    4812         */
    4813        public static String center(String str, int size, char padChar) {
    4814            if (str == null || size <= 0) {
    4815                return str;
    4816            }
    4817            int strLen = str.length();
    4818            int pads = size - strLen;
    4819            if (pads <= 0) {
    4820                return str;
    4821            }
    4822            str = leftPad(str, strLen + pads / 2, padChar);
    4823            str = rightPad(str, size, padChar);
    4824            return str;
    4825        }
    4826
    4827        /**
    4828         * <p>Centers a String in a larger String of size <code>size</code>.
    4829         * Uses a supplied String as the value to pad the String with.</p>
    4830         *
    4831         * <p>If the size is less than the String length, the String is returned.
    4832         * A <code>null</code> String returns <code>null</code>.
    4833         * A negative size is treated as zero.</p>
    4834         *
    4835         * <pre>
    4836         * StringUtils.center(null, *, *)     = null
    4837         * StringUtils.center("", 4, " ")     = "    "
    4838         * StringUtils.center("ab", -1, " ")  = "ab"
    4839         * StringUtils.center("ab", 4, " ")   = " ab"
    4840         * StringUtils.center("abcd", 2, " ") = "abcd"
    4841         * StringUtils.center("a", 4, " ")    = " a  "
    4842         * StringUtils.center("a", 4, "yz")   = "yayz"
    4843         * StringUtils.center("abc", 7, null) = "  abc  "
    4844         * StringUtils.center("abc", 7, "")   = "  abc  "
    4845         * </pre>
    4846         *
    4847         * @param str  the String to center, may be null
    4848         * @param size  the int size of new String, negative treated as zero
    4849         * @param padStr  the String to pad the new String with, must not be null or empty
    4850         * @return centered String, <code>null</code> if null String input
    4851         * @throws IllegalArgumentException if padStr is <code>null</code> or empty
    4852         */
    4853        public static String center(String str, int size, String padStr) {
    4854            if (str == null || size <= 0) {
    4855                return str;
    4856            }
    4857            if (isEmpty(padStr)) {
    4858                padStr = " ";
    4859            }
    4860            int strLen = str.length();
    4861            int pads = size - strLen;
    4862            if (pads <= 0) {
    4863                return str;
    4864            }
    4865            str = leftPad(str, strLen + pads / 2, padStr);
    4866            str = rightPad(str, size, padStr);
    4867            return str;
    4868        }
    4869
    4870        // Case conversion
    4871        //-----------------------------------------------------------------------
    4872        /**
    4873         * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
    4874         *
    4875         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    4876         *
    4877         * <pre>
    4878         * StringUtils.upperCase(null)  = null
    4879         * StringUtils.upperCase("")    = ""
    4880         * StringUtils.upperCase("aBc") = "ABC"
    4881         * </pre>
    4882         *
    4883         * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
    4884         * the result of this method is affected by the current locale.
    4885         * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    4886         * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    4887         *
    4888         * @param str  the String to upper case, may be null
    4889         * @return the upper cased String, <code>null</code> if null String input
    4890         */
    4891        public static String upperCase(String str) {
    4892            if (str == null) {
    4893                return null;
    4894            }
    4895            return str.toUpperCase();
    4896        }
    4897
    4898        /**
    4899         * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
    4900         *
    4901         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    4902         *
    4903         * <pre>
    4904         * StringUtils.upperCase(null, Locale.ENGLISH)  = null
    4905         * StringUtils.upperCase("", Locale.ENGLISH)    = ""
    4906         * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
    4907         * </pre>
    4908         *
    4909         * @param str  the String to upper case, may be null
    4910         * @param locale  the locale that defines the case transformation rules, must not be null
    4911         * @return the upper cased String, <code>null</code> if null String input
    4912         * @since 2.5
    4913         */
    4914        public static String upperCase(String str, Locale locale) {
    4915            if (str == null) {
    4916                return null;
    4917            }
    4918            return str.toUpperCase(locale);
    4919        }
    4920
    4921        /**
    4922         * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
    4923         *
    4924         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    4925         *
    4926         * <pre>
    4927         * StringUtils.lowerCase(null)  = null
    4928         * StringUtils.lowerCase("")    = ""
    4929         * StringUtils.lowerCase("aBc") = "abc"
    4930         * </pre>
    4931         *
    4932         * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
    4933         * the result of this method is affected by the current locale.
    4934         * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
    4935         * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
    4936         *
    4937         * @param str  the String to lower case, may be null
    4938         * @return the lower cased String, <code>null</code> if null String input
    4939         */
    4940        public static String lowerCase(String str) {
    4941            if (str == null) {
    4942                return null;
    4943            }
    4944            return str.toLowerCase();
    4945        }
    4946
    4947        /**
    4948         * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
    4949         *
    4950         * <p>A <code>null</code> input String returns <code>null</code>.</p>
    4951         *
    4952         * <pre>
    4953         * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
    4954         * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
    4955         * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
    4956         * </pre>
    4957         *
    4958         * @param str  the String to lower case, may be null
    4959         * @param locale  the locale that defines the case transformation rules, must not be null
    4960         * @return the lower cased String, <code>null</code> if null String input
    4961         * @since 2.5
    4962         */
    4963        public static String lowerCase(String str, Locale locale) {
    4964            if (str == null) {
    4965                return null;
    4966            }
    4967            return str.toLowerCase(locale);
    4968        }
    4969
    4970        /**
    4971         * <p>Capitalizes a String changing the first letter to title case as
    4972         * per {@link Character#toTitleCase(char)}. No other letters are changed.</p>
    4973         *
    4974         * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
    4975         * A <code>null</code> input String returns <code>null</code>.</p>
    4976         *
    4977         * <pre>
    4978         * StringUtils.capitalize(null)  = null
    4979         * StringUtils.capitalize("")    = ""
    4980         * StringUtils.capitalize("cat") = "Cat"
    4981         * StringUtils.capitalize("cAt") = "CAt"
    4982         * </pre>
    4983         *
    4984         * @param cs the String to capitalize, may be null
    4985         * @return the capitalized String, <code>null</code> if null String input
    4986         * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
    4987         * @see #uncapitalize(CharSequence)
    4988         * @since 2.0
    4989         * @since 3.0 Changed signature from capitalize(String) to capitalize(CharSequence)
    4990         */
    4991        public static String capitalize(CharSequence cs) {
    4992            if (cs == null ) {
    4993                return null;
    4994            }
    4995            int strLen;
    4996            if ((strLen = cs.length()) == 0) {
    4997                return cs.toString();
    4998            }
    4999            return new StringBuilder(strLen)
    5000                .append(Character.toTitleCase(cs.charAt(0)))
    5001                .append(CharSequenceUtils.subSequence(cs, 1))
    5002                .toString();
    5003        }
    5004
    5005        /**
    5006         * <p>Uncapitalizes a CharSequence changing the first letter to title case as
    5007         * per {@link Character#toLowerCase(char)}. No other letters are changed.</p>
    5008         *
    5009         * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
    5010         * A <code>null</code> input String returns <code>null</code>.</p>
    5011         *
    5012         * <pre>
    5013         * StringUtils.uncapitalize(null)  = null
    5014         * StringUtils.uncapitalize("")    = ""
    5015         * StringUtils.uncapitalize("Cat") = "cat"
    5016         * StringUtils.uncapitalize("CAT") = "cAT"
    5017         * </pre>
    5018         *
    5019         * @param cs the String to uncapitalize, may be null
    5020         * @return the uncapitalized String, <code>null</code> if null String input
    5021         * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
    5022         * @see #capitalize(CharSequence)
    5023         * @since 2.0
    5024         * @since 3.0 Changed signature from uncapitalize(String) to uncapitalize(CharSequence)
    5025         */
    5026        public static String uncapitalize(CharSequence cs) {
    5027            if (cs == null ) {
    5028                return null;
    5029            }
    5030            int strLen;
    5031            if ((strLen = cs.length()) == 0) {
    5032                return cs.toString();
    5033            }
    5034            return new StringBuilder(strLen)
    5035                .append(Character.toLowerCase(cs.charAt(0)))
    5036                .append(CharSequenceUtils.subSequence(cs, 1))
    5037                .toString();
    5038        }
    5039
    5040        /**
    5041         * <p>Swaps the case of a String changing upper and title case to
    5042         * lower case, and lower case to upper case.</p>
    5043         *
    5044         * <ul>
    5045         *  <li>Upper case character converts to Lower case</li>
    5046         *  <li>Title case character converts to Lower case</li>
    5047         *  <li>Lower case character converts to Upper case</li>
    5048         * </ul>
    5049         *
    5050         * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
    5051         * A <code>null</code> input String returns <code>null</code>.</p>
    5052         *
    5053         * <pre>
    5054         * StringUtils.swapCase(null)                 = null
    5055         * StringUtils.swapCase("")                   = ""
    5056         * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
    5057         * </pre>
    5058         *
    5059         * <p>NOTE: This method changed in Lang version 2.0.
    5060         * It no longer performs a word based algorithm.
    5061         * If you only use ASCII, you will notice no change.
    5062         * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
    5063         *
    5064         * @param str  the String to swap case, may be null
    5065         * @return the changed String, <code>null</code> if null String input
    5066         */
    5067        public static String swapCase(String str) {
    5068            int strLen;
    5069            if (str == null || (strLen = str.length()) == 0) {
    5070                return str;
    5071            }
    5072            StringBuilder buffer = new StringBuilder(strLen);
    5073
    5074            char ch = 0;
    5075            for (int i = 0; i < strLen; i++) {
    5076                ch = str.charAt(i);
    5077                if (Character.isUpperCase(ch)) {
    5078                    ch = Character.toLowerCase(ch);
    5079                } else if (Character.isTitleCase(ch)) {
    5080                    ch = Character.toLowerCase(ch);
    5081                } else if (Character.isLowerCase(ch)) {
    5082                    ch = Character.toUpperCase(ch);
    5083                }
    5084                buffer.append(ch);
    5085            }
    5086            return buffer.toString();
    5087        }
    5088
    5089        // Count matches
    5090        //-----------------------------------------------------------------------
    5091        /**
    5092         * <p>Counts how many times the substring appears in the larger String.</p>
    5093         *
    5094         * <p>A <code>null</code> or empty ("") String input returns <code>0</code>.</p>
    5095         *
    5096         * <pre>
    5097         * StringUtils.countMatches(null, *)       = 0
    5098         * StringUtils.countMatches("", *)         = 0
    5099         * StringUtils.countMatches("abba", null)  = 0
    5100         * StringUtils.countMatches("abba", "")    = 0
    5101         * StringUtils.countMatches("abba", "a")   = 2
    5102         * StringUtils.countMatches("abba", "ab")  = 1
    5103         * StringUtils.countMatches("abba", "xxx") = 0
    5104         * </pre>
    5105         *
    5106         * @param str  the String to check, may be null
    5107         * @param sub  the substring to count, may be null
    5108         * @return the number of occurrences, 0 if either String is <code>null</code>
    5109         */
    5110        public static int countMatches(String str, String sub) {
    5111            if (isEmpty(str) || isEmpty(sub)) {
    5112                return 0;
    5113            }
    5114            int count = 0;
    5115            int idx = 0;
    5116            while ((idx = str.indexOf(sub, idx)) != INDEX_NOT_FOUND) {
    5117                count++;
    5118                idx += sub.length();
    5119            }
    5120            return count;
    5121        }
    5122
    5123        // Character Tests
    5124        //-----------------------------------------------------------------------
    5125        /**
    5126         * <p>Checks if the CharSequence contains only unicode letters.</p>
    5127         *
    5128         * <p><code>null</code> will return <code>false</code>.
    5129         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5130         *
    5131         * <pre>
    5132         * StringUtils.isAlpha(null)   = false
    5133         * StringUtils.isAlpha("")     = true
    5134         * StringUtils.isAlpha("  ")   = false
    5135         * StringUtils.isAlpha("abc")  = true
    5136         * StringUtils.isAlpha("ab2c") = false
    5137         * StringUtils.isAlpha("ab-c") = false
    5138         * </pre>
    5139         *
    5140         * @param cs  the CharSequence to check, may be null
    5141         * @return <code>true</code> if only contains letters, and is non-null
    5142         * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
    5143         */
    5144        public static boolean isAlpha(CharSequence cs) {
    5145            if (cs == null) {
    5146                return false;
    5147            }
    5148            int sz = cs.length();
    5149            for (int i = 0; i < sz; i++) {
    5150                if (Character.isLetter(cs.charAt(i)) == false) {
    5151                    return false;
    5152                }
    5153            }
    5154            return true;
    5155        }
    5156
    5157        /**
    5158         * <p>Checks if the CharSequence contains only unicode letters and
    5159         * space (' ').</p>
    5160         *
    5161         * <p><code>null</code> will return <code>false</code>
    5162         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5163         *
    5164         * <pre>
    5165         * StringUtils.isAlphaSpace(null)   = false
    5166         * StringUtils.isAlphaSpace("")     = true
    5167         * StringUtils.isAlphaSpace("  ")   = true
    5168         * StringUtils.isAlphaSpace("abc")  = true
    5169         * StringUtils.isAlphaSpace("ab c") = true
    5170         * StringUtils.isAlphaSpace("ab2c") = false
    5171         * StringUtils.isAlphaSpace("ab-c") = false
    5172         * </pre>
    5173         *
    5174         * @param cs  the CharSequence to check, may be null
    5175         * @return <code>true</code> if only contains letters and space,
    5176         *  and is non-null
    5177         * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
    5178         */
    5179        public static boolean isAlphaSpace(CharSequence cs) {
    5180            if (cs == null) {
    5181                return false;
    5182            }
    5183            int sz = cs.length();
    5184            for (int i = 0; i < sz; i++) {
    5185                if ((Character.isLetter(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
    5186                    return false;
    5187                }
    5188            }
    5189            return true;
    5190        }
    5191
    5192        /**
    5193         * <p>Checks if the CharSequence contains only unicode letters or digits.</p>
    5194         *
    5195         * <p><code>null</code> will return <code>false</code>.
    5196         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5197         *
    5198         * <pre>
    5199         * StringUtils.isAlphanumeric(null)   = false
    5200         * StringUtils.isAlphanumeric("")     = true
    5201         * StringUtils.isAlphanumeric("  ")   = false
    5202         * StringUtils.isAlphanumeric("abc")  = true
    5203         * StringUtils.isAlphanumeric("ab c") = false
    5204         * StringUtils.isAlphanumeric("ab2c") = true
    5205         * StringUtils.isAlphanumeric("ab-c") = false
    5206         * </pre>
    5207         *
    5208         * @param cs  the CharSequence to check, may be null
    5209         * @return <code>true</code> if only contains letters or digits,
    5210         *  and is non-null
    5211         * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
    5212         */
    5213        public static boolean isAlphanumeric(CharSequence cs) {
    5214            if (cs == null) {
    5215                return false;
    5216            }
    5217            int sz = cs.length();
    5218            for (int i = 0; i < sz; i++) {
    5219                if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
    5220                    return false;
    5221                }
    5222            }
    5223            return true;
    5224        }
    5225
    5226        /**
    5227         * <p>Checks if the CharSequence contains only unicode letters, digits
    5228         * or space (<code>' '</code>).</p>
    5229         *
    5230         * <p><code>null</code> will return <code>false</code>.
    5231         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5232         *
    5233         * <pre>
    5234         * StringUtils.isAlphanumeric(null)   = false
    5235         * StringUtils.isAlphanumeric("")     = true
    5236         * StringUtils.isAlphanumeric("  ")   = true
    5237         * StringUtils.isAlphanumeric("abc")  = true
    5238         * StringUtils.isAlphanumeric("ab c") = true
    5239         * StringUtils.isAlphanumeric("ab2c") = true
    5240         * StringUtils.isAlphanumeric("ab-c") = false
    5241         * </pre>
    5242         *
    5243         * @param cs  the CharSequence to check, may be null
    5244         * @return <code>true</code> if only contains letters, digits or space,
    5245         *  and is non-null
    5246         * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
    5247         */
    5248        public static boolean isAlphanumericSpace(CharSequence cs) {
    5249            if (cs == null) {
    5250                return false;
    5251            }
    5252            int sz = cs.length();
    5253            for (int i = 0; i < sz; i++) {
    5254                if ((Character.isLetterOrDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
    5255                    return false;
    5256                }
    5257            }
    5258            return true;
    5259        }
    5260
    5261        /**
    5262         * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
    5263         *
    5264         * <p><code>null</code> will return <code>false</code>.
    5265         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5266         *
    5267         * <pre>
    5268         * StringUtils.isAsciiPrintable(null)     = false
    5269         * StringUtils.isAsciiPrintable("")       = true
    5270         * StringUtils.isAsciiPrintable(" ")      = true
    5271         * StringUtils.isAsciiPrintable("Ceki")   = true
    5272         * StringUtils.isAsciiPrintable("ab2c")   = true
    5273         * StringUtils.isAsciiPrintable("!ab-c~") = true
    5274         * StringUtils.isAsciiPrintable("\u0020") = true
    5275         * StringUtils.isAsciiPrintable("\u0021") = true
    5276         * StringUtils.isAsciiPrintable("\u007e") = true
    5277         * StringUtils.isAsciiPrintable("\u007f") = false
    5278         * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
    5279         * </pre>
    5280         *
    5281         * @param cs the CharSequence to check, may be null
    5282         * @return <code>true</code> if every character is in the range
    5283         *  32 thru 126
    5284         * @since 2.1
    5285         * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
    5286         */
    5287        public static boolean isAsciiPrintable(CharSequence cs) {
    5288            if (cs == null) {
    5289                return false;
    5290            }
    5291            int sz = cs.length();
    5292            for (int i = 0; i < sz; i++) {
    5293                if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
    5294                    return false;
    5295                }
    5296            }
    5297            return true;
    5298        }
    5299
    5300        /**
    5301         * <p>Checks if the CharSequence contains only unicode digits.
    5302         * A decimal point is not a unicode digit and returns false.</p>
    5303         *
    5304         * <p><code>null</code> will return <code>false</code>.
    5305         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5306         *
    5307         * <pre>
    5308         * StringUtils.isNumeric(null)   = false
    5309         * StringUtils.isNumeric("")     = true
    5310         * StringUtils.isNumeric("  ")   = false
    5311         * StringUtils.isNumeric("123")  = true
    5312         * StringUtils.isNumeric("12 3") = false
    5313         * StringUtils.isNumeric("ab2c") = false
    5314         * StringUtils.isNumeric("12-3") = false
    5315         * StringUtils.isNumeric("12.3") = false
    5316         * </pre>
    5317         *
    5318         * @param cs  the CharSequence to check, may be null
    5319         * @return <code>true</code> if only contains digits, and is non-null
    5320         * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
    5321         */
    5322        public static boolean isNumeric(CharSequence cs) {
    5323            if (cs == null) {
    5324                return false;
    5325            }
    5326            int sz = cs.length();
    5327            for (int i = 0; i < sz; i++) {
    5328                if (Character.isDigit(cs.charAt(i)) == false) {
    5329                    return false;
    5330                }
    5331            }
    5332            return true;
    5333        }
    5334
    5335        /**
    5336         * <p>Checks if the CharSequence contains only unicode digits or space
    5337         * (<code>' '</code>).
    5338         * A decimal point is not a unicode digit and returns false.</p>
    5339         *
    5340         * <p><code>null</code> will return <code>false</code>.
    5341         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5342         *
    5343         * <pre>
    5344         * StringUtils.isNumeric(null)   = false
    5345         * StringUtils.isNumeric("")     = true
    5346         * StringUtils.isNumeric("  ")   = true
    5347         * StringUtils.isNumeric("123")  = true
    5348         * StringUtils.isNumeric("12 3") = true
    5349         * StringUtils.isNumeric("ab2c") = false
    5350         * StringUtils.isNumeric("12-3") = false
    5351         * StringUtils.isNumeric("12.3") = false
    5352         * </pre>
    5353         *
    5354         * @param cs  the CharSequence to check, may be null
    5355         * @return <code>true</code> if only contains digits or space,
    5356         *  and is non-null
    5357         * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
    5358         */
    5359        public static boolean isNumericSpace(CharSequence cs) {
    5360            if (cs == null) {
    5361                return false;
    5362            }
    5363            int sz = cs.length();
    5364            for (int i = 0; i < sz; i++) {
    5365                if ((Character.isDigit(cs.charAt(i)) == false) && (cs.charAt(i) != ' ')) {
    5366                    return false;
    5367                }
    5368            }
    5369            return true;
    5370        }
    5371
    5372        /**
    5373         * <p>Checks if the CharSequence contains only whitespace.</p>
    5374         *
    5375         * <p><code>null</code> will return <code>false</code>.
    5376         * An empty CharSequence (length()=0) will return <code>true</code>.</p>
    5377         *
    5378         * <pre>
    5379         * StringUtils.isWhitespace(null)   = false
    5380         * StringUtils.isWhitespace("")     = true
    5381         * StringUtils.isWhitespace("  ")   = true
    5382         * StringUtils.isWhitespace("abc")  = false
    5383         * StringUtils.isWhitespace("ab2c") = false
    5384         * StringUtils.isWhitespace("ab-c") = false
    5385         * </pre>
    5386         *
    5387         * @param cs  the CharSequence to check, may be null
    5388         * @return <code>true</code> if only contains whitespace, and is non-null
    5389         * @since 2.0
    5390         * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
    5391         */
    5392        public static boolean isWhitespace(CharSequence cs) {
    5393            if (cs == null) {
    5394                return false;
    5395            }
    5396            int sz = cs.length();
    5397            for (int i = 0; i < sz; i++) {
    5398                if ((Character.isWhitespace(cs.charAt(i)) == false)) {
    5399                    return false;
    5400                }
    5401            }
    5402            return true;
    5403        }
    5404
    5405        /**
    5406         * <p>Checks if the CharSequence contains only lowercase characters.</p>
    5407         *
    5408         * <p><code>null</code> will return <code>false</code>.
    5409         * An empty CharSequence (length()=0) will return <code>false</code>.</p>
    5410         *
    5411         * <pre>
    5412         * StringUtils.isAllLowerCase(null)   = false
    5413         * StringUtils.isAllLowerCase("")     = false
    5414         * StringUtils.isAllLowerCase("  ")   = false
    5415         * StringUtils.isAllLowerCase("abc")  = true
    5416         * StringUtils.isAllLowerCase("abC") = false
    5417         * </pre>
    5418         *
    5419         * @param cs  the CharSequence to check, may be null
    5420         * @return <code>true</code> if only contains lowercase characters, and is non-null
    5421         * @since 2.5
    5422         * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
    5423         */
    5424        public static boolean isAllLowerCase(CharSequence cs) {
    5425            if (cs == null || isEmpty(cs)) {
    5426                return false;
    5427            }
    5428            int sz = cs.length();
    5429            for (int i = 0; i < sz; i++) {
    5430                if (Character.isLowerCase(cs.charAt(i)) == false) {
    5431                    return false;
    5432                }
    5433            }
    5434            return true;
    5435        }
    5436
    5437        /**
    5438         * <p>Checks if the CharSequence contains only uppercase characters.</p>
    5439         *
    5440         * <p><code>null</code> will return <code>false</code>.
    5441         * An empty String (length()=0) will return <code>false</code>.</p>
    5442         *
    5443         * <pre>
    5444         * StringUtils.isAllUpperCase(null)   = false
    5445         * StringUtils.isAllUpperCase("")     = false
    5446         * StringUtils.isAllUpperCase("  ")   = false
    5447         * StringUtils.isAllUpperCase("ABC")  = true
    5448         * StringUtils.isAllUpperCase("aBC") = false
    5449         * </pre>
    5450         *
    5451         * @param cs the CharSequence to check, may be null
    5452         * @return <code>true</code> if only contains uppercase characters, and is non-null
    5453         * @since 2.5
    5454         * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
    5455         */
    5456        public static boolean isAllUpperCase(CharSequence cs) {
    5457            if (cs == null || isEmpty(cs)) {
    5458                return false;
    5459            }
    5460            int sz = cs.length();
    5461            for (int i = 0; i < sz; i++) {
    5462                if (Character.isUpperCase(cs.charAt(i)) == false) {
    5463                    return false;
    5464                }
    5465            }
    5466            return true;
    5467        }
    5468
    5469        // Defaults
    5470        //-----------------------------------------------------------------------
    5471        /**
    5472         * <p>Returns either the passed in String,
    5473         * or if the String is <code>null</code>, an empty String ("").</p>
    5474         *
    5475         * <pre>
    5476         * StringUtils.defaultString(null)  = ""
    5477         * StringUtils.defaultString("")    = ""
    5478         * StringUtils.defaultString("bat") = "bat"
    5479         * </pre>
    5480         *
    5481         * @see ObjectUtils#toString(Object)
    5482         * @see String#valueOf(Object)
    5483         * @param str  the String to check, may be null
    5484         * @return the passed in String, or the empty String if it
    5485         *  was <code>null</code>
    5486         */
    5487        public static String defaultString(String str) {
    5488            return str == null ? EMPTY : str;
    5489        }
    5490
    5491        /**
    5492         * <p>Returns either the passed in String, or if the String is
    5493         * <code>null</code>, the value of <code>defaultStr</code>.</p>
    5494         *
    5495         * <pre>
    5496         * StringUtils.defaultString(null, "NULL")  = "NULL"
    5497         * StringUtils.defaultString("", "NULL")    = ""
    5498         * StringUtils.defaultString("bat", "NULL") = "bat"
    5499         * </pre>
    5500         *
    5501         * @see ObjectUtils#toString(Object,String)
    5502         * @see String#valueOf(Object)
    5503         * @param str  the String to check, may be null
    5504         * @param defaultStr  the default String to return
    5505         *  if the input is <code>null</code>, may be null
    5506         * @return the passed in String, or the default if it was <code>null</code>
    5507         */
    5508        public static String defaultString(String str, String defaultStr) {
    5509            return str == null ? defaultStr : str;
    5510        }
    5511
    5512        /**
    5513         * <p>Returns either the passed in CharSequence, or if the CharSequence is
    5514         * empty or <code>null</code>, the value of <code>defaultStr</code>.</p>
    5515         *
    5516         * <pre>
    5517         * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
    5518         * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
    5519         * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
    5520         * StringUtils.defaultIfEmpty("", null)      = null
    5521         * </pre>
    5522         * @param <T> the specific kind of CharSequence
    5523         * @param str  the CharSequence to check, may be null
    5524         * @param defaultStr  the default CharSequence to return
    5525         *  if the input is empty ("") or <code>null</code>, may be null
    5526         * @return the passed in CharSequence, or the default
    5527         * @see StringUtils#defaultString(String, String)
    5528         */
    5529        public static <T extends CharSequence> T defaultIfEmpty(T str, T defaultStr) {
    5530            return StringUtils.isEmpty(str) ? defaultStr : str;
    5531        }
    5532
    5533        // Reversing
    5534        //-----------------------------------------------------------------------
    5535        /**
    5536         * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
    5537         *
    5538         * <p>A <code>null</code> String returns <code>null</code>.</p>
    5539         *
    5540         * <pre>
    5541         * StringUtils.reverse(null)  = null
    5542         * StringUtils.reverse("")    = ""
    5543         * StringUtils.reverse("bat") = "tab"
    5544         * </pre>
    5545         *
    5546         * @param str  the String to reverse, may be null
    5547         * @return the reversed String, <code>null</code> if null String input
    5548         */
    5549        public static String reverse(String str) {
    5550            if (str == null) {
    5551                return null;
    5552            }
    5553            return new StringBuilder(str).reverse().toString();
    5554        }
    5555
    5556        /**
    5557         * <p>Reverses a String that is delimited by a specific character.</p>
    5558         *
    5559         * <p>The Strings between the delimiters are not reversed.
    5560         * Thus java.lang.String becomes String.lang.java (if the delimiter
    5561         * is <code>'.'</code>).</p>
    5562         *
    5563         * <pre>
    5564         * StringUtils.reverseDelimited(null, *)      = null
    5565         * StringUtils.reverseDelimited("", *)        = ""
    5566         * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
    5567         * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
    5568         * </pre>
    5569         *
    5570         * @param str  the String to reverse, may be null
    5571         * @param separatorChar  the separator character to use
    5572         * @return the reversed String, <code>null</code> if null String input
    5573         * @since 2.0
    5574         */
    5575        public static String reverseDelimited(String str, char separatorChar) {
    5576            if (str == null) {
    5577                return null;
    5578            }
    5579            // could implement manually, but simple way is to reuse other,
    5580            // probably slower, methods.
    5581            String[] strs = split(str, separatorChar);
    5582            ArrayUtils.reverse(strs);
    5583            return join(strs, separatorChar);
    5584        }
    5585
    5586        // Abbreviating
    5587        //-----------------------------------------------------------------------
    5588        /**
    5589         * <p>Abbreviates a String using ellipses. This will turn
    5590         * "Now is the time for all good men" into "Now is the time for..."</p>
    5591         *
    5592         * <p>Specifically:
    5593         * <ul>
    5594         *   <li>If <code>str</code> is less than <code>maxWidth</code> characters
    5595         *       long, return it.</li>
    5596         *   <li>Else abbreviate it to <code>(substring(str, 0, max-3) + "...")</code>.</li>
    5597         *   <li>If <code>maxWidth</code> is less than <code>4</code>, throw an
    5598         *       <code>IllegalArgumentException</code>.</li>
    5599         *   <li>In no case will it return a String of length greater than
    5600         *       <code>maxWidth</code>.</li>
    5601         * </ul>
    5602         * </p>
    5603         *
    5604         * <pre>
    5605         * StringUtils.abbreviate(null, *)      = null
    5606         * StringUtils.abbreviate("", 4)        = ""
    5607         * StringUtils.abbreviate("abcdefg", 6) = "abc..."
    5608         * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
    5609         * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
    5610         * StringUtils.abbreviate("abcdefg", 4) = "a..."
    5611         * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
    5612         * </pre>
    5613         *
    5614         * @param str  the String to check, may be null
    5615         * @param maxWidth  maximum length of result String, must be at least 4
    5616         * @return abbreviated String, <code>null</code> if null String input
    5617         * @throws IllegalArgumentException if the width is too small
    5618         * @since 2.0
    5619         */
    5620        public static String abbreviate(String str, int maxWidth) {
    5621            return abbreviate(str, 0, maxWidth);
    5622        }
    5623
    5624        /**
    5625         * <p>Abbreviates a String using ellipses. This will turn
    5626         * "Now is the time for all good men" into "...is the time for..."</p>
    5627         *
    5628         * <p>Works like <code>abbreviate(String, int)</code>, but allows you to specify
    5629         * a "left edge" offset.  Note that this left edge is not necessarily going to
    5630         * be the leftmost character in the result, or the first character following the
    5631         * ellipses, but it will appear somewhere in the result.
    5632         *
    5633         * <p>In no case will it return a String of length greater than
    5634         * <code>maxWidth</code>.</p>
    5635         *
    5636         * <pre>
    5637         * StringUtils.abbreviate(null, *, *)                = null
    5638         * StringUtils.abbreviate("", 0, 4)                  = ""
    5639         * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
    5640         * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
    5641         * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
    5642         * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
    5643         * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
    5644         * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
    5645         * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
    5646         * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
    5647         * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
    5648         * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
    5649         * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
    5650         * </pre>
    5651         *
    5652         * @param str  the String to check, may be null
    5653         * @param offset  left edge of source String
    5654         * @param maxWidth  maximum length of result String, must be at least 4
    5655         * @return abbreviated String, <code>null</code> if null String input
    5656         * @throws IllegalArgumentException if the width is too small
    5657         * @since 2.0
    5658         */
    5659        public static String abbreviate(String str, int offset, int maxWidth) {
    5660            if (str == null) {
    5661                return null;
    5662            }
    5663            if (maxWidth < 4) {
    5664                throw new IllegalArgumentException("Minimum abbreviation width is 4");
    5665            }
    5666            if (str.length() <= maxWidth) {
    5667                return str;
    5668            }
    5669            if (offset > str.length()) {
    5670                offset = str.length();
    5671            }
    5672            if ((str.length() - offset) < (maxWidth - 3)) {
    5673                offset = str.length() - (maxWidth - 3);
    5674            }
    5675            final String abrevMarker = "...";
    5676            if (offset <= 4) {
    5677                return str.substring(0, maxWidth - 3) + abrevMarker;
    5678            }
    5679            if (maxWidth < 7) {
    5680                throw new IllegalArgumentException("Minimum abbreviation width with offset is 7");
    5681            }
    5682            if ((offset + (maxWidth - 3)) < str.length()) {
    5683                return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
    5684            }
    5685            return abrevMarker + str.substring(str.length() - (maxWidth - 3));
    5686        }
    5687
    5688        /**
    5689         * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
    5690         * replacement String.</p>
    5691         *
    5692         * <p>This abbreviation only occurs if the following criteria is met:
    5693         * <ul>
    5694         * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
    5695         * <li>The length to truncate to is less than the length of the supplied String</li>
    5696         * <li>The length to truncate to is greater than 0</li>
    5697         * <li>The abbreviated String will have enough room for the length supplied replacement String
    5698         * and the first and last characters of the supplied String for abbreviation</li>
    5699         * </ul>
    5700         * Otherwise, the returned String will be the same as the supplied String for abbreviation.
    5701         * </p>
    5702         *
    5703         * <pre>
    5704         * StringUtils.abbreviateMiddle(null, null, 0)      = null
    5705         * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
    5706         * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
    5707         * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
    5708         * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
    5709         * </pre>
    5710         *
    5711         * @param str  the String to abbreviate, may be null
    5712         * @param middle the String to replace the middle characters with, may be null
    5713         * @param length the length to abbreviate <code>str</code> to.
    5714         * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
    5715         * @since 2.5
    5716         */
    5717        public static String abbreviateMiddle(String str, String middle, int length) {
    5718            if (isEmpty(str) || isEmpty(middle)) {
    5719                return str;
    5720            }
    5721
    5722            if (length >= str.length() || length < (middle.length()+2)) {
    5723                return str;
    5724            }
    5725
    5726            int targetSting = length-middle.length();
    5727            int startOffset = targetSting/2+targetSting%2;
    5728            int endOffset = str.length()-targetSting/2;
    5729
    5730            StringBuilder builder = new StringBuilder(length);
    5731            builder.append(str.substring(0,startOffset));
    5732            builder.append(middle);
    5733            builder.append(str.substring(endOffset));
    5734
    5735            return builder.toString();
    5736        }
    5737
    5738        // Difference
    5739        //-----------------------------------------------------------------------
    5740        /**
    5741         * <p>Compares two Strings, and returns the portion where they differ.
    5742         * (More precisely, return the remainder of the second String,
    5743         * starting from where it's different from the first.)</p>
    5744         *
    5745         * <p>For example,
    5746         * <code>difference("i am a machine", "i am a robot") -> "robot"</code>.</p>
    5747         *
    5748         * <pre>
    5749         * StringUtils.difference(null, null) = null
    5750         * StringUtils.difference("", "") = ""
    5751         * StringUtils.difference("", "abc") = "abc"
    5752         * StringUtils.difference("abc", "") = ""
    5753         * StringUtils.difference("abc", "abc") = ""
    5754         * StringUtils.difference("ab", "abxyz") = "xyz"
    5755         * StringUtils.difference("abcde", "abxyz") = "xyz"
    5756         * StringUtils.difference("abcde", "xyz") = "xyz"
    5757         * </pre>
    5758         *
    5759         * @param str1  the first String, may be null
    5760         * @param str2  the second String, may be null
    5761         * @return the portion of str2 where it differs from str1; returns the
    5762         * empty String if they are equal
    5763         * @since 2.0
    5764         */
    5765        public static String difference(String str1, String str2) {
    5766            if (str1 == null) {
    5767                return str2;
    5768            }
    5769            if (str2 == null) {
    5770                return str1;
    5771            }
    5772            int at = indexOfDifference(str1, str2);
    5773            if (at == INDEX_NOT_FOUND) {
    5774                return EMPTY;
    5775            }
    5776            return str2.substring(at);
    5777        }
    5778
    5779        /**
    5780         * <p>Compares two CharSequences, and returns the index at which the
    5781         * CharSequences begin to differ.</p>
    5782         *
    5783         * <p>For example,
    5784         * <code>indexOfDifference("i am a machine", "i am a robot") -> 7</code></p>
    5785         *
    5786         * <pre>
    5787         * StringUtils.indexOfDifference(null, null) = -1
    5788         * StringUtils.indexOfDifference("", "") = -1
    5789         * StringUtils.indexOfDifference("", "abc") = 0
    5790         * StringUtils.indexOfDifference("abc", "") = 0
    5791         * StringUtils.indexOfDifference("abc", "abc") = -1
    5792         * StringUtils.indexOfDifference("ab", "abxyz") = 2
    5793         * StringUtils.indexOfDifference("abcde", "abxyz") = 2
    5794         * StringUtils.indexOfDifference("abcde", "xyz") = 0
    5795         * </pre>
    5796         *
    5797         * @param cs1  the first CharSequence, may be null
    5798         * @param cs2  the second CharSequence, may be null
    5799         * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
    5800         * @since 2.0
    5801         * @since 3.0 Changed signature from indexOfDifference(String, String) to indexOfDifference(CharSequence, CharSequence)
    5802         */
    5803        public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
    5804            if (cs1 == cs2) {
    5805                return INDEX_NOT_FOUND;
    5806            }
    5807            if (cs1 == null || cs2 == null) {
    5808                return 0;
    5809            }
    5810            int i;
    5811            for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
    5812                if (cs1.charAt(i) != cs2.charAt(i)) {
    5813                    break;
    5814                }
    5815            }
    5816            if (i < cs2.length() || i < cs1.length()) {
    5817                return i;
    5818            }
    5819            return INDEX_NOT_FOUND;
    5820        }
    5821
    5822        /**
    5823         * <p>Compares all CharSequences in an array and returns the index at which the
    5824         * CharSequences begin to differ.</p>
    5825         *
    5826         * <p>For example,
    5827         * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7</code></p>
    5828         *
    5829         * <pre>
    5830         * StringUtils.indexOfDifference(null) = -1
    5831         * StringUtils.indexOfDifference(new String[] {}) = -1
    5832         * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
    5833         * StringUtils.indexOfDifference(new String[] {null, null}) = -1
    5834         * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
    5835         * StringUtils.indexOfDifference(new String[] {"", null}) = 0
    5836         * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
    5837         * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
    5838         * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
    5839         * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
    5840         * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
    5841         * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
    5842         * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
    5843         * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
    5844         * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
    5845         * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
    5846         * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
    5847         * </pre>
    5848         *
    5849         * @param css  array of CharSequences, entries may be null
    5850         * @return the index where the strings begin to differ; -1 if they are all equal
    5851         * @since 2.4
    5852         * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
    5853         */
    5854        public static int indexOfDifference(CharSequence... css) {
    5855            if (css == null || css.length <= 1) {
    5856                return INDEX_NOT_FOUND;
    5857            }
    5858            boolean anyStringNull = false;
    5859            boolean allStringsNull = true;
    5860            int arrayLen = css.length;
    5861            int shortestStrLen = Integer.MAX_VALUE;
    5862            int longestStrLen = 0;
    5863
    5864            // find the min and max string lengths; this avoids checking to make
    5865            // sure we are not exceeding the length of the string each time through
    5866            // the bottom loop.
    5867            for (int i = 0; i < arrayLen; i++) {
    5868                if (css[i] == null) {
    5869                    anyStringNull = true;
    5870                    shortestStrLen = 0;
    5871                } else {
    5872                    allStringsNull = false;
    5873                    shortestStrLen = Math.min(css[i].length(), shortestStrLen);
    5874                    longestStrLen = Math.max(css[i].length(), longestStrLen);
    5875                }
    5876            }
    5877
    5878            // handle lists containing all nulls or all empty strings
    5879            if (allStringsNull || (longestStrLen == 0 && !anyStringNull)) {
    5880                return INDEX_NOT_FOUND;
    5881            }
    5882
    5883            // handle lists containing some nulls or some empty strings
    5884            if (shortestStrLen == 0) {
    5885                return 0;
    5886            }
    5887
    5888            // find the position with the first difference across all strings
    5889            int firstDiff = -1;
    5890            for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
    5891                char comparisonChar = css[0].charAt(stringPos);
    5892                for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
    5893                    if (css[arrayPos].charAt(stringPos) != comparisonChar) {
    5894                        firstDiff = stringPos;
    5895                        break;
    5896                    }
    5897                }
    5898                if (firstDiff != -1) {
    5899                    break;
    5900                }
    5901            }
    5902
    5903            if (firstDiff == -1 && shortestStrLen != longestStrLen) {
    5904                // we compared all of the characters up to the length of the
    5905                // shortest string and didn't find a match, but the string lengths
    5906                // vary, so return the length of the shortest string.
    5907                return shortestStrLen;
    5908            }
    5909            return firstDiff;
    5910        }
    5911
    5912        /**
    5913         * <p>Compares all Strings in an array and returns the initial sequence of
    5914         * characters that is common to all of them.</p>
    5915         *
    5916         * <p>For example,
    5917         * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "</code></p>
    5918         *
    5919         * <pre>
    5920         * StringUtils.getCommonPrefix(null) = ""
    5921         * StringUtils.getCommonPrefix(new String[] {}) = ""
    5922         * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
    5923         * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
    5924         * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
    5925         * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
    5926         * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
    5927         * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
    5928         * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
    5929         * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
    5930         * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
    5931         * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
    5932         * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
    5933         * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
    5934         * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
    5935         * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
    5936         * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
    5937         * </pre>
    5938         *
    5939         * @param strs  array of String objects, entries may be null
    5940         * @return the initial sequence of characters that are common to all Strings
    5941         * in the array; empty String if the array is null, the elements are all null
    5942         * or if there is no common prefix.
    5943         * @since 2.4
    5944         */
    5945        public static String getCommonPrefix(String... strs) {
    5946            if (strs == null || strs.length == 0) {
    5947                return EMPTY;
    5948            }
    5949            int smallestIndexOfDiff = indexOfDifference(strs);
    5950            if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
    5951                // all strings were identical
    5952                if (strs[0] == null) {
    5953                    return EMPTY;
    5954                }
    5955                return strs[0];
    5956            } else if (smallestIndexOfDiff == 0) {
    5957                // there were no common initial characters
    5958                return EMPTY;
    5959            } else {
    5960                // we found a common initial character sequence
    5961                return strs[0].substring(0, smallestIndexOfDiff);
    5962            }
    5963        }
    5964
    5965        // Misc
    5966        //-----------------------------------------------------------------------
    5967        /**
    5968         * <p>Find the Levenshtein distance between two Strings.</p>
    5969         *
    5970         * <p>This is the number of changes needed to change one String into
    5971         * another, where each change is a single character modification (deletion,
    5972         * insertion or substitution).</p>
    5973         *
    5974         * <p>The previous implementation of the Levenshtein distance algorithm
    5975         * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
    5976         *
    5977         * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
    5978         * which can occur when my Java implementation is used with very large strings.<br>
    5979         * This implementation of the Levenshtein distance algorithm
    5980         * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
    5981         *
    5982         * <pre>
    5983         * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
    5984         * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
    5985         * StringUtils.getLevenshteinDistance("","")               = 0
    5986         * StringUtils.getLevenshteinDistance("","a")              = 1
    5987         * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
    5988         * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
    5989         * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
    5990         * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
    5991         * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
    5992         * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
    5993         * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
    5994         * </pre>
    5995         *
    5996         * @param s  the first String, must not be null
    5997         * @param t  the second String, must not be null
    5998         * @return result distance
    5999         * @throws IllegalArgumentException if either String input <code>null</code>
    6000         * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to getLevenshteinDistance(CharSequence, CharSequence)
    6001         */
    6002        public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    6003            if (s == null || t == null) {
    6004                throw new IllegalArgumentException("Strings must not be null");
    6005            }
    6006
    6007            /*
    6008               The difference between this impl. and the previous is that, rather
    6009               than creating and retaining a matrix of size s.length()+1 by t.length()+1,
    6010               we maintain two single-dimensional arrays of length s.length()+1.  The first, d,
    6011               is the 'current working' distance array that maintains the newest distance cost
    6012               counts as we iterate through the characters of String s.  Each time we increment
    6013               the index of String t we are comparing, d is copied to p, the second int[].  Doing so
    6014               allows us to retain the previous cost counts as required by the algorithm (taking
    6015               the minimum of the cost count to the left, up one, and diagonally up and to the left
    6016               of the current cost count being calculated).  (Note that the arrays aren't really
    6017               copied anymore, just switched...this is clearly much better than cloning an array
    6018               or doing a System.arraycopy() each time  through the outer loop.)
    6019
    6020               Effectively, the difference between the two implementations is this one does not
    6021               cause an out of memory condition when calculating the LD over two very large strings.
    6022             */
    6023
    6024            int n = s.length(); // length of s
    6025            int m = t.length(); // length of t
    6026
    6027            if (n == 0) {
    6028                return m;
    6029            } else if (m == 0) {
    6030                return n;
    6031            }
    6032
    6033            if (n > m) {
    6034                // swap the input strings to consume less memory
    6035                CharSequence tmp = s;
    6036                s = t;
    6037                t = tmp;
    6038                n = m;
    6039                m = t.length();
    6040            }
    6041
    6042            int p[] = new int[n+1]; //'previous' cost array, horizontally
    6043            int d[] = new int[n+1]; // cost array, horizontally
    6044            int _d[]; //placeholder to assist in swapping p and d
    6045
    6046            // indexes into strings s and t
    6047            int i; // iterates through s
    6048            int j; // iterates through t
    6049
    6050            char t_j; // jth character of t
    6051
    6052            int cost; // cost
    6053
    6054            for (i = 0; i<=n; i++) {
    6055                p[i] = i;
    6056            }
    6057
    6058            for (j = 1; j<=m; j++) {
    6059                t_j = t.charAt(j-1);
    6060                d[0] = j;
    6061
    6062                for (i=1; i<=n; i++) {
    6063                    cost = s.charAt(i-1)==t_j ? 0 : 1;
    6064                    // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
    6065                    d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1),  p[i-1]+cost);
    6066                }
    6067
    6068                // copy current distance counts to 'previous row' distance counts
    6069                _d = p;
    6070                p = d;
    6071                d = _d;
    6072            }
    6073
    6074            // our last action in the above loop was to switch d and p, so p now
    6075            // actually has the most recent cost counts
    6076            return p[n];
    6077        }
    6078
    6079        // startsWith
    6080        //-----------------------------------------------------------------------
    6081
    6082        /**
    6083         * <p>Check if a String starts with a specified prefix.</p>
    6084         *
    6085         * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
    6086         * references are considered to be equal. The comparison is case sensitive.</p>
    6087         *
    6088         * <pre>
    6089         * StringUtils.startsWith(null, null)      = true
    6090         * StringUtils.startsWith(null, "abc")     = false
    6091         * StringUtils.startsWith("abcdef", null)  = false
    6092         * StringUtils.startsWith("abcdef", "abc") = true
    6093         * StringUtils.startsWith("ABCDEF", "abc") = false
    6094         * </pre>
    6095         *
    6096         * @see java.lang.String#startsWith(String)
    6097         * @param str  the String to check, may be null
    6098         * @param prefix the prefix to find, may be null
    6099         * @return <code>true</code> if the String starts with the prefix, case sensitive, or
    6100         *  both <code>null</code>
    6101         * @since 2.4
    6102         */
    6103        public static boolean startsWith(String str, String prefix) {
    6104            return startsWith(str, prefix, false);
    6105        }
    6106
    6107        /**
    6108         * <p>Case insensitive check if a String starts with a specified prefix.</p>
    6109         *
    6110         * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
    6111         * references are considered to be equal. The comparison is case insensitive.</p>
    6112         *
    6113         * <pre>
    6114         * StringUtils.startsWithIgnoreCase(null, null)      = true
    6115         * StringUtils.startsWithIgnoreCase(null, "abc")     = false
    6116         * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
    6117         * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
    6118         * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
    6119         * </pre>
    6120         *
    6121         * @see java.lang.String#startsWith(String)
    6122         * @param str  the String to check, may be null
    6123         * @param prefix the prefix to find, may be null
    6124         * @return <code>true</code> if the String starts with the prefix, case insensitive, or
    6125         *  both <code>null</code>
    6126         * @since 2.4
    6127         */
    6128        public static boolean startsWithIgnoreCase(String str, String prefix) {
    6129            return startsWith(str, prefix, true);
    6130        }
    6131
    6132        /**
    6133         * <p>Check if a String starts with a specified prefix (optionally case insensitive).</p>
    6134         *
    6135         * @see java.lang.String#startsWith(String)
    6136         * @param str  the String to check, may be null
    6137         * @param prefix the prefix to find, may be null
    6138         * @param ignoreCase inidicates whether the compare should ignore case
    6139         *  (case insensitive) or not.
    6140         * @return <code>true</code> if the String starts with the prefix or
    6141         *  both <code>null</code>
    6142         */
    6143        private static boolean startsWith(String str, String prefix, boolean ignoreCase) {
    6144            if (str == null || prefix == null) {
    6145                return (str == null && prefix == null);
    6146            }
    6147            if (prefix.length() > str.length()) {
    6148                return false;
    6149            }
    6150            return str.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
    6151        }
    6152
    6153        /**
    6154         * <p>Check if a String starts with any of an array of specified strings.</p>
    6155         *
    6156         * <pre>
    6157         * StringUtils.startsWithAny(null, null)      = false
    6158         * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
    6159         * StringUtils.startsWithAny("abcxyz", null)     = false
    6160         * StringUtils.startsWithAny("abcxyz", new String[] {""}) = false
    6161         * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
    6162         * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
    6163         * </pre>
    6164         *
    6165         * @param string  the String to check, may be null
    6166         * @param searchStrings the Strings to find, may be null or empty
    6167         * @return <code>true</code> if the String starts with any of the the prefixes, case insensitive, or
    6168         *  both <code>null</code>
    6169         * @since 2.5
    6170         */
    6171        public static boolean startsWithAny(String string, String... searchStrings) {
    6172            if (isEmpty(string) || ArrayUtils.isEmpty(searchStrings)) {
    6173                return false;
    6174            }
    6175            for (int i = 0; i < searchStrings.length; i++) {
    6176                String searchString = searchStrings[i];
    6177                if (StringUtils.startsWith(string, searchString)) {
    6178                    return true;
    6179                }
    6180            }
    6181            return false;
    6182        }
    6183
    6184        // endsWith
    6185        //-----------------------------------------------------------------------
    6186
    6187        /**
    6188         * <p>Check if a String ends with a specified suffix.</p>
    6189         *
    6190         * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
    6191         * references are considered to be equal. The comparison is case sensitive.</p>
    6192         *
    6193         * <pre>
    6194         * StringUtils.endsWith(null, null)      = true
    6195         * StringUtils.endsWith(null, "def")     = false
    6196         * StringUtils.endsWith("abcdef", null)  = false
    6197         * StringUtils.endsWith("abcdef", "def") = true
    6198         * StringUtils.endsWith("ABCDEF", "def") = false
    6199         * StringUtils.endsWith("ABCDEF", "cde") = false
    6200         * </pre>
    6201         *
    6202         * @see java.lang.String#endsWith(String)
    6203         * @param str  the String to check, may be null
    6204         * @param suffix the suffix to find, may be null
    6205         * @return <code>true</code> if the String ends with the suffix, case sensitive, or
    6206         *  both <code>null</code>
    6207         * @since 2.4
    6208         */
    6209        public static boolean endsWith(String str, String suffix) {
    6210            return endsWith(str, suffix, false);
    6211        }
    6212
    6213        /**
    6214         * <p>Case insensitive check if a String ends with a specified suffix.</p>
    6215         *
    6216         * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
    6217         * references are considered to be equal. The comparison is case insensitive.</p>
    6218         *
    6219         * <pre>
    6220         * StringUtils.endsWithIgnoreCase(null, null)      = true
    6221         * StringUtils.endsWithIgnoreCase(null, "def")     = false
    6222         * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
    6223         * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
    6224         * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
    6225         * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
    6226         * </pre>
    6227         *
    6228         * @see java.lang.String#endsWith(String)
    6229         * @param str  the String to check, may be null
    6230         * @param suffix the suffix to find, may be null
    6231         * @return <code>true</code> if the String ends with the suffix, case insensitive, or
    6232         *  both <code>null</code>
    6233         * @since 2.4
    6234         */
    6235        public static boolean endsWithIgnoreCase(String str, String suffix) {
    6236            return endsWith(str, suffix, true);
    6237        }
    6238
    6239        /**
    6240         * <p>Check if a String ends with a specified suffix (optionally case insensitive).</p>
    6241         *
    6242         * @see java.lang.String#endsWith(String)
    6243         * @param str  the String to check, may be null
    6244         * @param suffix the suffix to find, may be null
    6245         * @param ignoreCase inidicates whether the compare should ignore case
    6246         *  (case insensitive) or not.
    6247         * @return <code>true</code> if the String starts with the prefix or
    6248         *  both <code>null</code>
    6249         */
    6250        private static boolean endsWith(String str, String suffix, boolean ignoreCase) {
    6251            if (str == null || suffix == null) {
    6252                return str == null && suffix == null;
    6253            }
    6254            if (suffix.length() > str.length()) {
    6255                return false;
    6256            }
    6257            int strOffset = str.length() - suffix.length();
    6258            return str.regionMatches(ignoreCase, strOffset, suffix, 0, suffix.length());
    6259        }
    6260    }