View Javadoc

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