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