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