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