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