View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3;
18  
19  import java.io.UnsupportedEncodingException;
20  import java.nio.charset.Charset;
21  import java.text.Normalizer;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.regex.Pattern;
28  
29  /**
30   * <p>Operations on {@link java.lang.String} that are
31   * {@code null} safe.</p>
32   *
33   * <ul>
34   *  <li><b>IsEmpty/IsBlank</b>
35   *      - checks if a String contains text</li>
36   *  <li><b>Trim/Strip</b>
37   *      - removes leading and trailing whitespace</li>
38   *  <li><b>Equals</b>
39   *      - compares two strings null-safe</li>
40   *  <li><b>startsWith</b>
41   *      - check if a String starts with a prefix null-safe</li>
42   *  <li><b>endsWith</b>
43   *      - check if a String ends with a suffix null-safe</li>
44   *  <li><b>IndexOf/LastIndexOf/Contains</b>
45   *      - null-safe index-of checks
46   *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
47   *      - index-of any of a set of Strings</li>
48   *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
49   *      - does String contains only/none/any of these characters</li>
50   *  <li><b>Substring/Left/Right/Mid</b>
51   *      - null-safe substring extractions</li>
52   *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
53   *      - substring extraction relative to other strings</li>
54   *  <li><b>Split/Join</b>
55   *      - splits a String into an array of substrings and vice versa</li>
56   *  <li><b>Remove/Delete</b>
57   *      - removes part of a String</li>
58   *  <li><b>Replace/Overlay</b>
59   *      - Searches a String and replaces one String with another</li>
60   *  <li><b>Chomp/Chop</b>
61   *      - removes the last part of a String</li>
62   *  <li><b>AppendIfMissing</b>
63   *      - appends a suffix to the end of the String if not present</li>
64   *  <li><b>PrependIfMissing</b>
65   *      - prepends a prefix to the start of the String if not present</li>
66   *  <li><b>LeftPad/RightPad/Center/Repeat</b>
67   *      - pads a String</li>
68   *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
69   *      - changes the case of a String</li>
70   *  <li><b>CountMatches</b>
71   *      - counts the number of occurrences of one String in another</li>
72   *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
73   *      - checks the characters in a String</li>
74   *  <li><b>DefaultString</b>
75   *      - protects against a null input String</li>
76   *  <li><b>Rotate</b>
77   *      - rotate (circular shift) a String</li>
78   *  <li><b>Reverse/ReverseDelimited</b>
79   *      - reverses a String</li>
80   *  <li><b>Abbreviate</b>
81   *      - abbreviates a string using ellipsis</li>
82   *  <li><b>Difference</b>
83   *      - compares Strings and reports on their differences</li>
84   *  <li><b>LevenshteinDistance</b>
85   *      - the number of changes needed to change one String into another</li>
86   * </ul>
87   *
88   * <p>The {@code StringUtils} class defines certain words related to
89   * String handling.</p>
90   *
91   * <ul>
92   *  <li>null - {@code null}</li>
93   *  <li>empty - a zero-length string ({@code ""})</li>
94   *  <li>space - the space character ({@code ' '}, char 32)</li>
95   *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
96   *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
97   * </ul>
98   *
99   * <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
116 public 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