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