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