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