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