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