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    }