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