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