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 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         final int targetSting = length - middle.length();
410         final int startOffset = targetSting / 2 + targetSting % 2;
411         final int endOffset = str.length() - targetSting / 2;
412         return str.substring(0, startOffset) + middle + str.substring(endOffset);
413     }
414 
415     /**
416      * Appends the suffix to the end of the string if the string does not
417      * already end with the suffix.
418      *
419      * @param str The string.
420      * @param suffix The suffix to append to the end of the string.
421      * @param ignoreCase Indicates whether the compare should ignore case.
422      * @param suffixes Additional suffixes that are valid terminators (optional).
423      *
424      * @return A new String if suffix was appended, the same string otherwise.
425      */
426     private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
427         if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
428             return str;
429         }
430         if (ArrayUtils.isNotEmpty(suffixes)) {
431             for (final CharSequence s : suffixes) {
432                 if (endsWith(str, s, ignoreCase)) {
433                     return str;
434                 }
435             }
436         }
437         return str + suffix;
438     }
439 
440     /**
441      * Appends the suffix to the end of the string if the string does not
442      * already end with any of the suffixes.
443      *
444      * <pre>
445      * StringUtils.appendIfMissing(null, null)      = null
446      * StringUtils.appendIfMissing("abc", null)     = "abc"
447      * StringUtils.appendIfMissing("", "xyz"        = "xyz"
448      * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
449      * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
450      * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
451      * </pre>
452      * <p>With additional suffixes,</p>
453      * <pre>
454      * StringUtils.appendIfMissing(null, null, null)       = null
455      * StringUtils.appendIfMissing("abc", null, null)      = "abc"
456      * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
457      * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
458      * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
459      * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
460      * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
461      * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
462      * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
463      * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
464      * </pre>
465      *
466      * @param str The string.
467      * @param suffix The suffix to append to the end of the string.
468      * @param suffixes Additional suffixes that are valid terminators.
469      *
470      * @return A new String if suffix was appended, the same string otherwise.
471      *
472      * @since 3.2
473      */
474     public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
475         return appendIfMissing(str, suffix, false, suffixes);
476     }
477 
478     /**
479      * Appends the suffix to the end of the string if the string does not
480      * already end, case-insensitive, with any of the suffixes.
481      *
482      * <pre>
483      * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
484      * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
485      * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
486      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
487      * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
488      * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
489      * </pre>
490      * <p>With additional suffixes,</p>
491      * <pre>
492      * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
493      * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
494      * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
495      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
496      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
497      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
498      * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
499      * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
500      * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
501      * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
502      * </pre>
503      *
504      * @param str The string.
505      * @param suffix The suffix to append to the end of the string.
506      * @param suffixes Additional suffixes that are valid terminators.
507      *
508      * @return A new String if suffix was appended, the same string otherwise.
509      *
510      * @since 3.2
511      */
512     public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
513         return appendIfMissing(str, suffix, true, suffixes);
514     }
515 
516     /**
517      * Capitalizes a String changing the first character to title case as
518      * per {@link Character#toTitleCase(int)}. No other characters are changed.
519      *
520      * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
521      * A {@code null} input String returns {@code null}.</p>
522      *
523      * <pre>
524      * StringUtils.capitalize(null)    = null
525      * StringUtils.capitalize("")      = ""
526      * StringUtils.capitalize("cat")   = "Cat"
527      * StringUtils.capitalize("cAt")   = "CAt"
528      * StringUtils.capitalize("'cat'") = "'cat'"
529      * </pre>
530      *
531      * @param str the String to capitalize, may be null
532      * @return the capitalized String, {@code null} if null String input
533      * @see org.apache.commons.text.WordUtils#capitalize(String)
534      * @see #uncapitalize(String)
535      * @since 2.0
536      */
537     public static String capitalize(final String str) {
538         final int strLen = length(str);
539         if (strLen == 0) {
540             return str;
541         }
542 
543         final int firstCodepoint = str.codePointAt(0);
544         final int newCodePoint = Character.toTitleCase(firstCodepoint);
545         if (firstCodepoint == newCodePoint) {
546             // already capitalized
547             return str;
548         }
549 
550         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
551         int outOffset = 0;
552         newCodePoints[outOffset++] = newCodePoint; // copy the first code point
553         for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
554             final int codePoint = str.codePointAt(inOffset);
555             newCodePoints[outOffset++] = codePoint; // copy the remaining ones
556             inOffset += Character.charCount(codePoint);
557          }
558         return new String(newCodePoints, 0, outOffset);
559     }
560 
561     /**
562      * Centers a String in a larger String of size {@code size}
563      * using the space character (' ').
564      *
565      * <p>If the size is less than the String length, the original String is returned.
566      * A {@code null} String returns {@code null}.
567      * A negative size is treated as zero.</p>
568      *
569      * <p>Equivalent to {@code center(str, size, " ")}.</p>
570      *
571      * <pre>
572      * StringUtils.center(null, *)   = null
573      * StringUtils.center("", 4)     = "    "
574      * StringUtils.center("ab", -1)  = "ab"
575      * StringUtils.center("ab", 4)   = " ab "
576      * StringUtils.center("abcd", 2) = "abcd"
577      * StringUtils.center("a", 4)    = " a  "
578      * </pre>
579      *
580      * @param str  the String to center, may be null
581      * @param size  the int size of new String, negative treated as zero
582      * @return centered String, {@code null} if null String input
583      */
584     public static String center(final String str, final int size) {
585         return center(str, size, ' ');
586     }
587 
588     /**
589      * Centers a String in a larger String of size {@code size}.
590      * Uses a supplied character as the value to pad the String with.
591      *
592      * <p>If the size is less than the String length, the String is returned.
593      * A {@code null} String returns {@code null}.
594      * A negative size is treated as zero.</p>
595      *
596      * <pre>
597      * StringUtils.center(null, *, *)     = null
598      * StringUtils.center("", 4, ' ')     = "    "
599      * StringUtils.center("ab", -1, ' ')  = "ab"
600      * StringUtils.center("ab", 4, ' ')   = " ab "
601      * StringUtils.center("abcd", 2, ' ') = "abcd"
602      * StringUtils.center("a", 4, ' ')    = " a  "
603      * StringUtils.center("a", 4, 'y')    = "yayy"
604      * </pre>
605      *
606      * @param str  the String to center, may be null
607      * @param size  the int size of new String, negative treated as zero
608      * @param padChar  the character to pad the new String with
609      * @return centered String, {@code null} if null String input
610      * @since 2.0
611      */
612     public static String center(String str, final int size, final char padChar) {
613         if (str == null || size <= 0) {
614             return str;
615         }
616         final int strLen = str.length();
617         final int pads = size - strLen;
618         if (pads <= 0) {
619             return str;
620         }
621         str = leftPad(str, strLen + pads / 2, padChar);
622         return rightPad(str, size, padChar);
623     }
624 
625     /**
626      * Centers a String in a larger String of size {@code size}.
627      * Uses a supplied String as the value to pad the String with.
628      *
629      * <p>If the size is less than the String length, the String is returned.
630      * A {@code null} String returns {@code null}.
631      * A negative size is treated as zero.</p>
632      *
633      * <pre>
634      * StringUtils.center(null, *, *)     = null
635      * StringUtils.center("", 4, " ")     = "    "
636      * StringUtils.center("ab", -1, " ")  = "ab"
637      * StringUtils.center("ab", 4, " ")   = " ab "
638      * StringUtils.center("abcd", 2, " ") = "abcd"
639      * StringUtils.center("a", 4, " ")    = " a  "
640      * StringUtils.center("a", 4, "yz")   = "yayz"
641      * StringUtils.center("abc", 7, null) = "  abc  "
642      * StringUtils.center("abc", 7, "")   = "  abc  "
643      * </pre>
644      *
645      * @param str  the String to center, may be null
646      * @param size  the int size of new String, negative treated as zero
647      * @param padStr  the String to pad the new String with, must not be null or empty
648      * @return centered String, {@code null} if null String input
649      * @throws IllegalArgumentException if padStr is {@code null} or empty
650      */
651     public static String center(String str, final int size, String padStr) {
652         if (str == null || size <= 0) {
653             return str;
654         }
655         if (isEmpty(padStr)) {
656             padStr = SPACE;
657         }
658         final int strLen = str.length();
659         final int pads = size - strLen;
660         if (pads <= 0) {
661             return str;
662         }
663         str = leftPad(str, strLen + pads / 2, padStr);
664         return rightPad(str, size, padStr);
665     }
666 
667     /**
668      * Removes one newline from end of a String if it's there,
669      * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
670      * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
671      *
672      * <p>NOTE: This method changed in 2.0.
673      * It now more closely matches Perl chomp.</p>
674      *
675      * <pre>
676      * StringUtils.chomp(null)          = null
677      * StringUtils.chomp("")            = ""
678      * StringUtils.chomp("abc \r")      = "abc "
679      * StringUtils.chomp("abc\n")       = "abc"
680      * StringUtils.chomp("abc\r\n")     = "abc"
681      * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
682      * StringUtils.chomp("abc\n\r")     = "abc\n"
683      * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
684      * StringUtils.chomp("\r")          = ""
685      * StringUtils.chomp("\n")          = ""
686      * StringUtils.chomp("\r\n")        = ""
687      * </pre>
688      *
689      * @param str  the String to chomp a newline from, may be null
690      * @return String without newline, {@code null} if null String input
691      */
692     public static String chomp(final String str) {
693         if (isEmpty(str)) {
694             return str;
695         }
696 
697         if (str.length() == 1) {
698             final char ch = str.charAt(0);
699             if (ch == CharUtils.CR || ch == CharUtils.LF) {
700                 return EMPTY;
701             }
702             return str;
703         }
704 
705         int lastIdx = str.length() - 1;
706         final char last = str.charAt(lastIdx);
707 
708         if (last == CharUtils.LF) {
709             if (str.charAt(lastIdx - 1) == CharUtils.CR) {
710                 lastIdx--;
711             }
712         } else if (last != CharUtils.CR) {
713             lastIdx++;
714         }
715         return str.substring(0, lastIdx);
716     }
717 
718     /**
719      * Removes {@code separator} from the end of
720      * {@code str} if it's there, otherwise leave it alone.
721      *
722      * <p>NOTE: This method changed in version 2.0.
723      * It now more closely matches Perl chomp.
724      * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
725      * This method uses {@link String#endsWith(String)}.</p>
726      *
727      * <pre>
728      * StringUtils.chomp(null, *)         = null
729      * StringUtils.chomp("", *)           = ""
730      * StringUtils.chomp("foobar", "bar") = "foo"
731      * StringUtils.chomp("foobar", "baz") = "foobar"
732      * StringUtils.chomp("foo", "foo")    = ""
733      * StringUtils.chomp("foo ", "foo")   = "foo "
734      * StringUtils.chomp(" foo", "foo")   = " "
735      * StringUtils.chomp("foo", "foooo")  = "foo"
736      * StringUtils.chomp("foo", "")       = "foo"
737      * StringUtils.chomp("foo", null)     = "foo"
738      * </pre>
739      *
740      * @param str  the String to chomp from, may be null
741      * @param separator  separator String, may be null
742      * @return String without trailing separator, {@code null} if null String input
743      * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
744      */
745     @Deprecated
746     public static String chomp(final String str, final String separator) {
747         return removeEnd(str, separator);
748     }
749 
750     /**
751      * Remove the last character from a String.
752      *
753      * <p>If the String ends in {@code \r\n}, then remove both
754      * of them.</p>
755      *
756      * <pre>
757      * StringUtils.chop(null)          = null
758      * StringUtils.chop("")            = ""
759      * StringUtils.chop("abc \r")      = "abc "
760      * StringUtils.chop("abc\n")       = "abc"
761      * StringUtils.chop("abc\r\n")     = "abc"
762      * StringUtils.chop("abc")         = "ab"
763      * StringUtils.chop("abc\nabc")    = "abc\nab"
764      * StringUtils.chop("a")           = ""
765      * StringUtils.chop("\r")          = ""
766      * StringUtils.chop("\n")          = ""
767      * StringUtils.chop("\r\n")        = ""
768      * </pre>
769      *
770      * @param str  the String to chop last character from, may be null
771      * @return String without last character, {@code null} if null String input
772      */
773     public static String chop(final String str) {
774         if (str == null) {
775             return null;
776         }
777         final int strLen = str.length();
778         if (strLen < 2) {
779             return EMPTY;
780         }
781         final int lastIdx = strLen - 1;
782         final String ret = str.substring(0, lastIdx);
783         final char last = str.charAt(lastIdx);
784         if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
785             return ret.substring(0, lastIdx - 1);
786         }
787         return ret;
788     }
789 
790     /**
791      * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
792      * <ul>
793      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
794      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
795      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
796      * </ul>
797      *
798      * <p>This is a {@code null} safe version of :</p>
799      * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
800      *
801      * <p>{@code null} value is considered less than non-{@code null} value.
802      * Two {@code null} references are considered equal.</p>
803      *
804      * <pre>{@code
805      * StringUtils.compare(null, null)   = 0
806      * StringUtils.compare(null , "a")   < 0
807      * StringUtils.compare("a", null)   > 0
808      * StringUtils.compare("abc", "abc") = 0
809      * StringUtils.compare("a", "b")     < 0
810      * StringUtils.compare("b", "a")     > 0
811      * StringUtils.compare("a", "B")     > 0
812      * StringUtils.compare("ab", "abc")  < 0
813      * }</pre>
814      *
815      * @see #compare(String, String, boolean)
816      * @see String#compareTo(String)
817      * @param str1  the String to compare from
818      * @param str2  the String to compare to
819      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
820      * @since 3.5
821      */
822     public static int compare(final String str1, final String str2) {
823         return compare(str1, str2, true);
824     }
825 
826     /**
827      * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
828      * <ul>
829      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
830      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
831      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
832      * </ul>
833      *
834      * <p>This is a {@code null} safe version of :</p>
835      * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
836      *
837      * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
838      * Two {@code null} references are considered equal.</p>
839      *
840      * <pre>{@code
841      * StringUtils.compare(null, null, *)     = 0
842      * StringUtils.compare(null , "a", true)  < 0
843      * StringUtils.compare(null , "a", false) > 0
844      * StringUtils.compare("a", null, true)   > 0
845      * StringUtils.compare("a", null, false)  < 0
846      * StringUtils.compare("abc", "abc", *)   = 0
847      * StringUtils.compare("a", "b", *)       < 0
848      * StringUtils.compare("b", "a", *)       > 0
849      * StringUtils.compare("a", "B", *)       > 0
850      * StringUtils.compare("ab", "abc", *)    < 0
851      * }</pre>
852      *
853      * @see String#compareTo(String)
854      * @param str1  the String to compare from
855      * @param str2  the String to compare to
856      * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
857      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
858      * @since 3.5
859      */
860     public static int compare(final String str1, final String str2, final boolean nullIsLess) {
861         if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
862             return 0;
863         }
864         if (str1 == null) {
865             return nullIsLess ? -1 : 1;
866         }
867         if (str2 == null) {
868             return nullIsLess ? 1 : - 1;
869         }
870         return str1.compareTo(str2);
871     }
872 
873     /**
874      * Compare two Strings lexicographically, ignoring case differences,
875      * as per {@link String#compareToIgnoreCase(String)}, returning :
876      * <ul>
877      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
878      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
879      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
880      * </ul>
881      *
882      * <p>This is a {@code null} safe version of :</p>
883      * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
884      *
885      * <p>{@code null} value is considered less than non-{@code null} value.
886      * Two {@code null} references are considered equal.
887      * Comparison is case insensitive.</p>
888      *
889      * <pre>{@code
890      * StringUtils.compareIgnoreCase(null, null)   = 0
891      * StringUtils.compareIgnoreCase(null , "a")   < 0
892      * StringUtils.compareIgnoreCase("a", null)    > 0
893      * StringUtils.compareIgnoreCase("abc", "abc") = 0
894      * StringUtils.compareIgnoreCase("abc", "ABC") = 0
895      * StringUtils.compareIgnoreCase("a", "b")     < 0
896      * StringUtils.compareIgnoreCase("b", "a")     > 0
897      * StringUtils.compareIgnoreCase("a", "B")     < 0
898      * StringUtils.compareIgnoreCase("A", "b")     < 0
899      * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
900      * }</pre>
901      *
902      * @see #compareIgnoreCase(String, String, boolean)
903      * @see String#compareToIgnoreCase(String)
904      * @param str1  the String to compare from
905      * @param str2  the String to compare to
906      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
907      *          ignoring case differences.
908      * @since 3.5
909      */
910     public static int compareIgnoreCase(final String str1, final String str2) {
911         return compareIgnoreCase(str1, str2, true);
912     }
913 
914     /**
915      * Compare two Strings lexicographically, ignoring case differences,
916      * as per {@link String#compareToIgnoreCase(String)}, returning :
917      * <ul>
918      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
919      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
920      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
921      * </ul>
922      *
923      * <p>This is a {@code null} safe version of :</p>
924      * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
925      *
926      * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
927      * Two {@code null} references are considered equal.
928      * Comparison is case insensitive.</p>
929      *
930      * <pre>{@code
931      * StringUtils.compareIgnoreCase(null, null, *)     = 0
932      * StringUtils.compareIgnoreCase(null , "a", true)  < 0
933      * StringUtils.compareIgnoreCase(null , "a", false) > 0
934      * StringUtils.compareIgnoreCase("a", null, true)   > 0
935      * StringUtils.compareIgnoreCase("a", null, false)  < 0
936      * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
937      * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
938      * StringUtils.compareIgnoreCase("a", "b", *)       < 0
939      * StringUtils.compareIgnoreCase("b", "a", *)       > 0
940      * StringUtils.compareIgnoreCase("a", "B", *)       < 0
941      * StringUtils.compareIgnoreCase("A", "b", *)       < 0
942      * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
943      * }</pre>
944      *
945      * @see String#compareToIgnoreCase(String)
946      * @param str1  the String to compare from
947      * @param str2  the String to compare to
948      * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
949      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
950      *          ignoring case differences.
951      * @since 3.5
952      */
953     public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
954         if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
955             return 0;
956         }
957         if (str1 == null) {
958             return nullIsLess ? -1 : 1;
959         }
960         if (str2 == null) {
961             return nullIsLess ? 1 : - 1;
962         }
963         return str1.compareToIgnoreCase(str2);
964     }
965 
966     /**
967      * Checks if CharSequence contains a search CharSequence, handling {@code null}.
968      * This method uses {@link String#indexOf(String)} if possible.
969      *
970      * <p>A {@code null} CharSequence will return {@code false}.</p>
971      *
972      * <pre>
973      * StringUtils.contains(null, *)     = false
974      * StringUtils.contains(*, null)     = false
975      * StringUtils.contains("", "")      = true
976      * StringUtils.contains("abc", "")   = true
977      * StringUtils.contains("abc", "a")  = true
978      * StringUtils.contains("abc", "z")  = false
979      * </pre>
980      *
981      * @param seq  the CharSequence to check, may be null
982      * @param searchSeq  the CharSequence to find, may be null
983      * @return true if the CharSequence contains the search CharSequence,
984      *  false if not or {@code null} string input
985      * @since 2.0
986      * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
987      */
988     public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
989         if (seq == null || searchSeq == null) {
990             return false;
991         }
992         return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
993     }
994 
995     /**
996      * Checks if CharSequence contains a search character, handling {@code null}.
997      * This method uses {@link String#indexOf(int)} if possible.
998      *
999      * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1000      *
1001      * <pre>
1002      * StringUtils.contains(null, *)    = false
1003      * StringUtils.contains("", *)      = false
1004      * StringUtils.contains("abc", 'a') = true
1005      * StringUtils.contains("abc", 'z') = false
1006      * </pre>
1007      *
1008      * @param seq  the CharSequence to check, may be null
1009      * @param searchChar  the character to find
1010      * @return true if the CharSequence contains the search character,
1011      *  false if not or {@code null} string input
1012      * @since 2.0
1013      * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1014      */
1015     public static boolean contains(final CharSequence seq, final int searchChar) {
1016         if (isEmpty(seq)) {
1017             return false;
1018         }
1019         return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1020     }
1021 
1022     /**
1023      * Checks if the CharSequence contains any character in the given
1024      * set of characters.
1025      *
1026      * <p>A {@code null} CharSequence will return {@code false}.
1027      * A {@code null} or zero length search array will return {@code false}.</p>
1028      *
1029      * <pre>
1030      * StringUtils.containsAny(null, *)                  = false
1031      * StringUtils.containsAny("", *)                    = false
1032      * StringUtils.containsAny(*, null)                  = false
1033      * StringUtils.containsAny(*, [])                    = false
1034      * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1035      * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1036      * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1037      * StringUtils.containsAny("aba", ['z'])             = false
1038      * </pre>
1039      *
1040      * @param cs  the CharSequence to check, may be null
1041      * @param searchChars  the chars to search for, may be null
1042      * @return the {@code true} if any of the chars are found,
1043      * {@code false} if no match or null input
1044      * @since 2.4
1045      * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1046      */
1047     public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1048         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1049             return false;
1050         }
1051         final int csLength = cs.length();
1052         final int searchLength = searchChars.length;
1053         final int csLast = csLength - 1;
1054         final int searchLast = searchLength - 1;
1055         for (int i = 0; i < csLength; i++) {
1056             final char ch = cs.charAt(i);
1057             for (int j = 0; j < searchLength; j++) {
1058                 if (searchChars[j] == ch) {
1059                     if (!Character.isHighSurrogate(ch)) {
1060                         // ch is in the Basic Multilingual Plane
1061                         return true;
1062                     }
1063                     if (j == searchLast) {
1064                         // missing low surrogate, fine, like String.indexOf(String)
1065                         return true;
1066                     }
1067                     if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1068                         return true;
1069                     }
1070                 }
1071             }
1072         }
1073         return false;
1074     }
1075 
1076     /**
1077      * Checks if the CharSequence contains any character in the given set of characters.
1078      *
1079      * <p>
1080      * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1081      * {@code false}.
1082      * </p>
1083      *
1084      * <pre>
1085      * StringUtils.containsAny(null, *)               = false
1086      * StringUtils.containsAny("", *)                 = false
1087      * StringUtils.containsAny(*, null)               = false
1088      * StringUtils.containsAny(*, "")                 = false
1089      * StringUtils.containsAny("zzabyycdxx", "za")    = true
1090      * StringUtils.containsAny("zzabyycdxx", "by")    = true
1091      * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1092      * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1093      * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1094      * StringUtils.containsAny("aba", "z")            = false
1095      * </pre>
1096      *
1097      * @param cs
1098      *            the CharSequence to check, may be null
1099      * @param searchChars
1100      *            the chars to search for, may be null
1101      * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1102      * @since 2.4
1103      * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1104      */
1105     public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1106         if (searchChars == null) {
1107             return false;
1108         }
1109         return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1110     }
1111 
1112     /**
1113      * Checks if the CharSequence contains any of the CharSequences in the given array.
1114      *
1115      * <p>
1116      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1117      * return {@code false}.
1118      * </p>
1119      *
1120      * <pre>
1121      * StringUtils.containsAny(null, *)            = false
1122      * StringUtils.containsAny("", *)              = false
1123      * StringUtils.containsAny(*, null)            = false
1124      * StringUtils.containsAny(*, [])              = false
1125      * StringUtils.containsAny("abcd", "ab", null) = true
1126      * StringUtils.containsAny("abcd", "ab", "cd") = true
1127      * StringUtils.containsAny("abc", "d", "abc")  = true
1128      * </pre>
1129      *
1130      * @param cs The CharSequence to check, may be null
1131      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1132      *        null as well.
1133      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1134      * @since 3.4
1135      */
1136     public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1137         return containsAny(StringUtils::contains, cs, searchCharSequences);
1138     }
1139 
1140     /**
1141      * Checks if the CharSequence contains any of the CharSequences in the given array.
1142      *
1143      * <p>
1144      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1145      * return {@code false}.
1146      * </p>
1147      *
1148      * @param cs The CharSequence to check, may be null
1149      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1150      *        null as well.
1151      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1152      * @since 3.12.0
1153      */
1154     private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
1155         final CharSequence cs, final CharSequence... searchCharSequences) {
1156         if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
1157             return false;
1158         }
1159         for (final CharSequence searchCharSequence : searchCharSequences) {
1160             if (test.applyAsBoolean(cs, searchCharSequence)) {
1161                 return true;
1162             }
1163         }
1164         return false;
1165     }
1166 
1167     /**
1168      * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1169      *
1170      * <p>
1171      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1172      * return {@code false}.
1173      * </p>
1174      *
1175      * <pre>
1176      * StringUtils.containsAny(null, *)            = false
1177      * StringUtils.containsAny("", *)              = false
1178      * StringUtils.containsAny(*, null)            = false
1179      * StringUtils.containsAny(*, [])              = false
1180      * StringUtils.containsAny("abcd", "ab", null) = true
1181      * StringUtils.containsAny("abcd", "ab", "cd") = true
1182      * StringUtils.containsAny("abc", "d", "abc")  = true
1183      * StringUtils.containsAny("abc", "D", "ABC")  = true
1184      * StringUtils.containsAny("ABC", "d", "abc")  = true
1185      * </pre>
1186      *
1187      * @param cs The CharSequence to check, may be null
1188      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1189      *        null as well.
1190      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1191      * @since 3.12.0
1192      */
1193     public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1194         return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
1195     }
1196 
1197     /**
1198      * Checks if CharSequence contains a search CharSequence irrespective of case,
1199      * handling {@code null}. Case-insensitivity is defined as by
1200      * {@link String#equalsIgnoreCase(String)}.
1201      *
1202      * <p>A {@code null} CharSequence will return {@code false}.
1203      *
1204      * <pre>
1205      * StringUtils.containsIgnoreCase(null, *)    = false
1206      * StringUtils.containsIgnoreCase(*, null)    = false
1207      * StringUtils.containsIgnoreCase("", "")     = true
1208      * StringUtils.containsIgnoreCase("abc", "")  = true
1209      * StringUtils.containsIgnoreCase("abc", "a") = true
1210      * StringUtils.containsIgnoreCase("abc", "z") = false
1211      * StringUtils.containsIgnoreCase("abc", "A") = true
1212      * StringUtils.containsIgnoreCase("abc", "Z") = false
1213      * </pre>
1214      *
1215      * @param str  the CharSequence to check, may be null
1216      * @param searchStr  the CharSequence to find, may be null
1217      * @return true if the CharSequence contains the search CharSequence irrespective of
1218      * case or false if not or {@code null} string input
1219      * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1220      */
1221     public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1222         if (str == null || searchStr == null) {
1223             return false;
1224         }
1225         final int len = searchStr.length();
1226         final int max = str.length() - len;
1227         for (int i = 0; i <= max; i++) {
1228             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
1229                 return true;
1230             }
1231         }
1232         return false;
1233     }
1234 
1235     /**
1236      * Checks that the CharSequence does not contain certain characters.
1237      *
1238      * <p>A {@code null} CharSequence will return {@code true}.
1239      * A {@code null} invalid character array will return {@code true}.
1240      * An empty CharSequence (length()=0) always returns true.</p>
1241      *
1242      * <pre>
1243      * StringUtils.containsNone(null, *)       = true
1244      * StringUtils.containsNone(*, null)       = true
1245      * StringUtils.containsNone("", *)         = true
1246      * StringUtils.containsNone("ab", '')      = true
1247      * StringUtils.containsNone("abab", 'xyz') = true
1248      * StringUtils.containsNone("ab1", 'xyz')  = true
1249      * StringUtils.containsNone("abz", 'xyz')  = false
1250      * </pre>
1251      *
1252      * @param cs  the CharSequence to check, may be null
1253      * @param searchChars  an array of invalid chars, may be null
1254      * @return true if it contains none of the invalid chars, or is null
1255      * @since 2.0
1256      * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1257      */
1258     public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1259         if (cs == null || searchChars == null) {
1260             return true;
1261         }
1262         final int csLen = cs.length();
1263         final int csLast = csLen - 1;
1264         final int searchLen = searchChars.length;
1265         final int searchLast = searchLen - 1;
1266         for (int i = 0; i < csLen; i++) {
1267             final char ch = cs.charAt(i);
1268             for (int j = 0; j < searchLen; j++) {
1269                 if (searchChars[j] == ch) {
1270                     if (!Character.isHighSurrogate(ch)) {
1271                         // ch is in the Basic Multilingual Plane
1272                         return false;
1273                     }
1274                     if (j == searchLast) {
1275                         // missing low surrogate, fine, like String.indexOf(String)
1276                         return false;
1277                     }
1278                     if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1279                         return false;
1280                     }
1281                 }
1282             }
1283         }
1284         return true;
1285     }
1286 
1287     /**
1288      * Checks that the CharSequence does not contain certain characters.
1289      *
1290      * <p>A {@code null} CharSequence will return {@code true}.
1291      * A {@code null} invalid character array will return {@code true}.
1292      * An empty String ("") always returns true.</p>
1293      *
1294      * <pre>
1295      * StringUtils.containsNone(null, *)       = true
1296      * StringUtils.containsNone(*, null)       = true
1297      * StringUtils.containsNone("", *)         = true
1298      * StringUtils.containsNone("ab", "")      = true
1299      * StringUtils.containsNone("abab", "xyz") = true
1300      * StringUtils.containsNone("ab1", "xyz")  = true
1301      * StringUtils.containsNone("abz", "xyz")  = false
1302      * </pre>
1303      *
1304      * @param cs  the CharSequence to check, may be null
1305      * @param invalidChars  a String of invalid chars, may be null
1306      * @return true if it contains none of the invalid chars, or is null
1307      * @since 2.0
1308      * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1309      */
1310     public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1311         if (invalidChars == null) {
1312             return true;
1313         }
1314         return containsNone(cs, invalidChars.toCharArray());
1315     }
1316 
1317     /**
1318      * Checks if the CharSequence contains only certain characters.
1319      *
1320      * <p>A {@code null} CharSequence will return {@code false}.
1321      * A {@code null} valid character array will return {@code false}.
1322      * An empty CharSequence (length()=0) always returns {@code true}.</p>
1323      *
1324      * <pre>
1325      * StringUtils.containsOnly(null, *)       = false
1326      * StringUtils.containsOnly(*, null)       = false
1327      * StringUtils.containsOnly("", *)         = true
1328      * StringUtils.containsOnly("ab", '')      = false
1329      * StringUtils.containsOnly("abab", 'abc') = true
1330      * StringUtils.containsOnly("ab1", 'abc')  = false
1331      * StringUtils.containsOnly("abz", 'abc')  = false
1332      * </pre>
1333      *
1334      * @param cs  the String to check, may be null
1335      * @param valid  an array of valid chars, may be null
1336      * @return true if it only contains valid chars and is non-null
1337      * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1338      */
1339     public static boolean containsOnly(final CharSequence cs, final char... valid) {
1340         // All these pre-checks are to maintain API with an older version
1341         if (valid == null || cs == null) {
1342             return false;
1343         }
1344         if (cs.length() == 0) {
1345             return true;
1346         }
1347         if (valid.length == 0) {
1348             return false;
1349         }
1350         return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1351     }
1352 
1353     /**
1354      * Checks if the CharSequence contains only certain characters.
1355      *
1356      * <p>A {@code null} CharSequence will return {@code false}.
1357      * A {@code null} valid character String will return {@code false}.
1358      * An empty String (length()=0) always returns {@code true}.</p>
1359      *
1360      * <pre>
1361      * StringUtils.containsOnly(null, *)       = false
1362      * StringUtils.containsOnly(*, null)       = false
1363      * StringUtils.containsOnly("", *)         = true
1364      * StringUtils.containsOnly("ab", "")      = false
1365      * StringUtils.containsOnly("abab", "abc") = true
1366      * StringUtils.containsOnly("ab1", "abc")  = false
1367      * StringUtils.containsOnly("abz", "abc")  = false
1368      * </pre>
1369      *
1370      * @param cs  the CharSequence to check, may be null
1371      * @param validChars  a String of valid chars, may be null
1372      * @return true if it only contains valid chars and is non-null
1373      * @since 2.0
1374      * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1375      */
1376     public static boolean containsOnly(final CharSequence cs, final String validChars) {
1377         if (cs == null || validChars == null) {
1378             return false;
1379         }
1380         return containsOnly(cs, validChars.toCharArray());
1381     }
1382 
1383     /**
1384      * Check whether the given CharSequence contains any whitespace characters.
1385      *
1386      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1387      *
1388      * @param seq the CharSequence to check (may be {@code null})
1389      * @return {@code true} if the CharSequence is not empty and
1390      * contains at least 1 (breaking) whitespace character
1391      * @since 3.0
1392      */
1393     // From org.springframework.util.StringUtils, under Apache License 2.0
1394     public static boolean containsWhitespace(final CharSequence seq) {
1395         if (isEmpty(seq)) {
1396             return false;
1397         }
1398         final int strLen = seq.length();
1399         for (int i = 0; i < strLen; i++) {
1400             if (Character.isWhitespace(seq.charAt(i))) {
1401                 return true;
1402             }
1403         }
1404         return false;
1405     }
1406 
1407     private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1408         for (int i = 0; i < decomposed.length(); i++) {
1409             final char charAt = decomposed.charAt(i);
1410             switch (charAt) {
1411             case '\u0141':
1412                 decomposed.setCharAt(i, 'L');
1413                 break;
1414             case '\u0142':
1415                 decomposed.setCharAt(i, 'l');
1416                 break;
1417             // D with stroke
1418             case '\u0110':
1419                 // LATIN CAPITAL LETTER D WITH STROKE
1420                 decomposed.setCharAt(i, 'D');
1421                 break;
1422             case '\u0111':
1423                 // LATIN SMALL LETTER D WITH STROKE
1424                 decomposed.setCharAt(i, 'd');
1425                 break;
1426             // I with bar
1427             case '\u0197':
1428                 decomposed.setCharAt(i, 'I');
1429                 break;
1430             case '\u0268':
1431                 decomposed.setCharAt(i, 'i');
1432                 break;
1433             case '\u1D7B':
1434                 decomposed.setCharAt(i, 'I');
1435                 break;
1436             case '\u1DA4':
1437                 decomposed.setCharAt(i, 'i');
1438                 break;
1439             case '\u1DA7':
1440                 decomposed.setCharAt(i, 'I');
1441                 break;
1442             // U with bar
1443             case '\u0244':
1444                 // LATIN CAPITAL LETTER U BAR
1445                 decomposed.setCharAt(i, 'U');
1446                 break;
1447             case '\u0289':
1448                 // LATIN SMALL LETTER U BAR
1449                 decomposed.setCharAt(i, 'u');
1450                 break;
1451             case '\u1D7E':
1452                 // LATIN SMALL CAPITAL LETTER U WITH STROKE
1453                 decomposed.setCharAt(i, 'U');
1454                 break;
1455             case '\u1DB6':
1456                 // MODIFIER LETTER SMALL U BAR
1457                 decomposed.setCharAt(i, 'u');
1458                 break;
1459             // T with stroke
1460             case '\u0166':
1461                 // LATIN CAPITAL LETTER T WITH STROKE
1462                 decomposed.setCharAt(i, 'T');
1463                 break;
1464             case '\u0167':
1465                 // LATIN SMALL LETTER T WITH STROKE
1466                 decomposed.setCharAt(i, 't');
1467                 break;
1468             default:
1469                 break;
1470             }
1471         }
1472     }
1473 
1474     /**
1475      * Counts how many times the char appears in the given string.
1476      *
1477      * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1478      *
1479      * <pre>
1480      * StringUtils.countMatches(null, *)     = 0
1481      * StringUtils.countMatches("", *)       = 0
1482      * StringUtils.countMatches("abba", 0)   = 0
1483      * StringUtils.countMatches("abba", 'a') = 2
1484      * StringUtils.countMatches("abba", 'b') = 2
1485      * StringUtils.countMatches("abba", 'x') = 0
1486      * </pre>
1487      *
1488      * @param str  the CharSequence to check, may be null
1489      * @param ch  the char to count
1490      * @return the number of occurrences, 0 if the CharSequence is {@code null}
1491      * @since 3.4
1492      */
1493     public static int countMatches(final CharSequence str, final char ch) {
1494         if (isEmpty(str)) {
1495             return 0;
1496         }
1497         int count = 0;
1498         // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1499         for (int i = 0; i < str.length(); i++) {
1500             if (ch == str.charAt(i)) {
1501                 count++;
1502             }
1503         }
1504         return count;
1505     }
1506 
1507     /**
1508      * Counts how many times the substring appears in the larger string.
1509      * Note that the code only counts non-overlapping matches.
1510      *
1511      * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1512      *
1513      * <pre>
1514      * StringUtils.countMatches(null, *)        = 0
1515      * StringUtils.countMatches("", *)          = 0
1516      * StringUtils.countMatches("abba", null)   = 0
1517      * StringUtils.countMatches("abba", "")     = 0
1518      * StringUtils.countMatches("abba", "a")    = 2
1519      * StringUtils.countMatches("abba", "ab")   = 1
1520      * StringUtils.countMatches("abba", "xxx")  = 0
1521      * StringUtils.countMatches("ababa", "aba") = 1
1522      * </pre>
1523      *
1524      * @param str  the CharSequence to check, may be null
1525      * @param sub  the substring to count, may be null
1526      * @return the number of occurrences, 0 if either CharSequence is {@code null}
1527      * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1528      */
1529     public static int countMatches(final CharSequence str, final CharSequence sub) {
1530         if (isEmpty(str) || isEmpty(sub)) {
1531             return 0;
1532         }
1533         int count = 0;
1534         int idx = 0;
1535         while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1536             count++;
1537             idx += sub.length();
1538         }
1539         return count;
1540     }
1541 
1542     /**
1543      * Returns either the passed in CharSequence, or if the CharSequence is
1544      * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.
1545      *
1546      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1547      *
1548      * <pre>
1549      * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1550      * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1551      * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1552      * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1553      * StringUtils.defaultIfBlank("", null)      = null
1554      * </pre>
1555      * @param <T> the specific kind of CharSequence
1556      * @param str the CharSequence to check, may be null
1557      * @param defaultStr  the default CharSequence to return
1558      *  if the input is whitespace, empty ("") or {@code null}, may be null
1559      * @return the passed in CharSequence, or the default
1560      * @see StringUtils#defaultString(String, String)
1561      */
1562     public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1563         return isBlank(str) ? defaultStr : str;
1564     }
1565 
1566     /**
1567      * Returns either the passed in CharSequence, or if the CharSequence is
1568      * empty or {@code null}, the value of {@code defaultStr}.
1569      *
1570      * <pre>
1571      * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1572      * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1573      * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1574      * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1575      * StringUtils.defaultIfEmpty("", null)      = null
1576      * </pre>
1577      * @param <T> the specific kind of CharSequence
1578      * @param str  the CharSequence to check, may be null
1579      * @param defaultStr  the default CharSequence to return
1580      *  if the input is empty ("") or {@code null}, may be null
1581      * @return the passed in CharSequence, or the default
1582      * @see StringUtils#defaultString(String, String)
1583      */
1584     public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1585         return isEmpty(str) ? defaultStr : str;
1586     }
1587 
1588     /**
1589      * Returns either the passed in String,
1590      * or if the String is {@code null}, an empty String ("").
1591      *
1592      * <pre>
1593      * StringUtils.defaultString(null)  = ""
1594      * StringUtils.defaultString("")    = ""
1595      * StringUtils.defaultString("bat") = "bat"
1596      * </pre>
1597      *
1598      * @see Objects#toString(Object, String)
1599      * @see String#valueOf(Object)
1600      * @param str  the String to check, may be null
1601      * @return the passed in String, or the empty String if it
1602      *  was {@code null}
1603      */
1604     public static String defaultString(final String str) {
1605         return Objects.toString(str, EMPTY);
1606     }
1607 
1608     /**
1609      * Returns either the given String, or if the String is
1610      * {@code null}, {@code nullDefault}.
1611      *
1612      * <pre>
1613      * StringUtils.defaultString(null, "NULL")  = "NULL"
1614      * StringUtils.defaultString("", "NULL")    = ""
1615      * StringUtils.defaultString("bat", "NULL") = "bat"
1616      * </pre>
1617      * <p>
1618      * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1619      * </p>
1620      * <pre>
1621      * Objects.toString(null, "NULL")  = "NULL"
1622      * Objects.toString("", "NULL")    = ""
1623      * Objects.toString("bat", "NULL") = "bat"
1624      * </pre>
1625      *
1626      * @see Objects#toString(Object, String)
1627      * @see String#valueOf(Object)
1628      * @param str  the String to check, may be null
1629      * @param nullDefault  the default String to return
1630      *  if the input is {@code null}, may be null
1631      * @return the passed in String, or the default if it was {@code null}
1632      * @deprecated Use {@link Objects#toString(Object, String)}
1633      */
1634     @Deprecated
1635     public static String defaultString(final String str, final String nullDefault) {
1636         return Objects.toString(str, nullDefault);
1637     }
1638 
1639     /**
1640      * Deletes all whitespaces from a String as defined by
1641      * {@link Character#isWhitespace(char)}.
1642      *
1643      * <pre>
1644      * StringUtils.deleteWhitespace(null)         = null
1645      * StringUtils.deleteWhitespace("")           = ""
1646      * StringUtils.deleteWhitespace("abc")        = "abc"
1647      * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1648      * </pre>
1649      *
1650      * @param str  the String to delete whitespace from, may be null
1651      * @return the String without whitespaces, {@code null} if null String input
1652      */
1653     public static String deleteWhitespace(final String str) {
1654         if (isEmpty(str)) {
1655             return str;
1656         }
1657         final int sz = str.length();
1658         final char[] chs = new char[sz];
1659         int count = 0;
1660         for (int i = 0; i < sz; i++) {
1661             if (!Character.isWhitespace(str.charAt(i))) {
1662                 chs[count++] = str.charAt(i);
1663             }
1664         }
1665         if (count == sz) {
1666             return str;
1667         }
1668         if (count == 0) {
1669             return EMPTY;
1670         }
1671         return new String(chs, 0, count);
1672     }
1673 
1674     /**
1675      * Compares two Strings, and returns the portion where they differ.
1676      * More precisely, return the remainder of the second String,
1677      * starting from where it's different from the first. This means that
1678      * the difference between "abc" and "ab" is the empty String and not "c".
1679      *
1680      * <p>For example,
1681      * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
1682      *
1683      * <pre>
1684      * StringUtils.difference(null, null)       = null
1685      * StringUtils.difference("", "")           = ""
1686      * StringUtils.difference("", "abc")        = "abc"
1687      * StringUtils.difference("abc", "")        = ""
1688      * StringUtils.difference("abc", "abc")     = ""
1689      * StringUtils.difference("abc", "ab")      = ""
1690      * StringUtils.difference("ab", "abxyz")    = "xyz"
1691      * StringUtils.difference("abcde", "abxyz") = "xyz"
1692      * StringUtils.difference("abcde", "xyz")   = "xyz"
1693      * </pre>
1694      *
1695      * @param str1  the first String, may be null
1696      * @param str2  the second String, may be null
1697      * @return the portion of str2 where it differs from str1; returns the
1698      * empty String if they are equal
1699      * @see #indexOfDifference(CharSequence,CharSequence)
1700      * @since 2.0
1701      */
1702     public static String difference(final String str1, final String str2) {
1703         if (str1 == null) {
1704             return str2;
1705         }
1706         if (str2 == null) {
1707             return str1;
1708         }
1709         final int at = indexOfDifference(str1, str2);
1710         if (at == INDEX_NOT_FOUND) {
1711             return EMPTY;
1712         }
1713         return str2.substring(at);
1714     }
1715 
1716     /**
1717      * Check if a CharSequence ends with a specified suffix.
1718      *
1719      * <p>{@code null}s are handled without exceptions. Two {@code null}
1720      * references are considered to be equal. The comparison is case-sensitive.</p>
1721      *
1722      * <pre>
1723      * StringUtils.endsWith(null, null)      = true
1724      * StringUtils.endsWith(null, "def")     = false
1725      * StringUtils.endsWith("abcdef", null)  = false
1726      * StringUtils.endsWith("abcdef", "def") = true
1727      * StringUtils.endsWith("ABCDEF", "def") = false
1728      * StringUtils.endsWith("ABCDEF", "cde") = false
1729      * StringUtils.endsWith("ABCDEF", "")    = true
1730      * </pre>
1731      *
1732      * @see String#endsWith(String)
1733      * @param str  the CharSequence to check, may be null
1734      * @param suffix the suffix to find, may be null
1735      * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
1736      *  both {@code null}
1737      * @since 2.4
1738      * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1739      */
1740     public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1741         return endsWith(str, suffix, false);
1742     }
1743 
1744     /**
1745      * Check if a CharSequence ends with a specified suffix (optionally case-insensitive).
1746      *
1747      * @see String#endsWith(String)
1748      * @param str  the CharSequence to check, may be null
1749      * @param suffix the suffix to find, may be null
1750      * @param ignoreCase indicates whether the compare should ignore case
1751      *  (case-insensitive) or not.
1752      * @return {@code true} if the CharSequence starts with the prefix or
1753      *  both {@code null}
1754      */
1755     private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
1756         if (str == null || suffix == null) {
1757             return str == suffix;
1758         }
1759         if (suffix.length() > str.length()) {
1760             return false;
1761         }
1762         final int strOffset = str.length() - suffix.length();
1763         return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
1764     }
1765 
1766     /**
1767      * Check if a CharSequence ends with any of the provided case-sensitive suffixes.
1768      *
1769      * <pre>
1770      * StringUtils.endsWithAny(null, null)                  = false
1771      * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1772      * StringUtils.endsWithAny("abcxyz", null)              = false
1773      * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1774      * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1775      * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1776      * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1777      * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1778      * </pre>
1779      *
1780      * @param sequence  the CharSequence to check, may be null
1781      * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
1782      * @see StringUtils#endsWith(CharSequence, CharSequence)
1783      * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
1784      *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
1785      * @since 3.0
1786      */
1787     public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1788         if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
1789             return false;
1790         }
1791         for (final CharSequence searchString : searchStrings) {
1792             if (endsWith(sequence, searchString)) {
1793                 return true;
1794             }
1795         }
1796         return false;
1797     }
1798 
1799     /**
1800      * Case-insensitive check if a CharSequence ends with a specified suffix.
1801      *
1802      * <p>{@code null}s are handled without exceptions. Two {@code null}
1803      * references are considered to be equal. The comparison is case insensitive.</p>
1804      *
1805      * <pre>
1806      * StringUtils.endsWithIgnoreCase(null, null)      = true
1807      * StringUtils.endsWithIgnoreCase(null, "def")     = false
1808      * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1809      * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1810      * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1811      * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1812      * </pre>
1813      *
1814      * @see String#endsWith(String)
1815      * @param str  the CharSequence to check, may be null
1816      * @param suffix the suffix to find, may be null
1817      * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
1818      *  both {@code null}
1819      * @since 2.4
1820      * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1821      */
1822     public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1823         return endsWith(str, suffix, true);
1824     }
1825 
1826     /**
1827      * Compares two CharSequences, returning {@code true} if they represent
1828      * equal sequences of characters.
1829      *
1830      * <p>{@code null}s are handled without exceptions. Two {@code null}
1831      * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
1832      *
1833      * <pre>
1834      * StringUtils.equals(null, null)   = true
1835      * StringUtils.equals(null, "abc")  = false
1836      * StringUtils.equals("abc", null)  = false
1837      * StringUtils.equals("abc", "abc") = true
1838      * StringUtils.equals("abc", "ABC") = false
1839      * </pre>
1840      *
1841      * @param cs1  the first CharSequence, may be {@code null}
1842      * @param cs2  the second CharSequence, may be {@code null}
1843      * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
1844      * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1845      * @see Object#equals(Object)
1846      * @see #equalsIgnoreCase(CharSequence, CharSequence)
1847      */
1848     public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1849         if (cs1 == cs2) {
1850             return true;
1851         }
1852         if (cs1 == null || cs2 == null) {
1853             return false;
1854         }
1855         if (cs1.length() != cs2.length()) {
1856             return false;
1857         }
1858         if (cs1 instanceof String && cs2 instanceof String) {
1859             return cs1.equals(cs2);
1860         }
1861         // Step-wise comparison
1862         final int length = cs1.length();
1863         for (int i = 0; i < length; i++) {
1864             if (cs1.charAt(i) != cs2.charAt(i)) {
1865                 return false;
1866             }
1867         }
1868         return true;
1869     }
1870 
1871     /**
1872      * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1873      * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
1874      *
1875      * <pre>
1876      * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1877      * StringUtils.equalsAny(null, null, null)    = true
1878      * StringUtils.equalsAny(null, "abc", "def")  = false
1879      * StringUtils.equalsAny("abc", null, "def")  = false
1880      * StringUtils.equalsAny("abc", "abc", "def") = true
1881      * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1882      * </pre>
1883      *
1884      * @param string to compare, may be {@code null}.
1885      * @param searchStrings a vararg of strings, may be {@code null}.
1886      * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
1887      * {@code false} if {@code searchStrings} is null or contains no matches.
1888      * @since 3.5
1889      */
1890     public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1891         if (ArrayUtils.isNotEmpty(searchStrings)) {
1892             for (final CharSequence next : searchStrings) {
1893                 if (equals(string, next)) {
1894                     return true;
1895                 }
1896             }
1897         }
1898         return false;
1899     }
1900 
1901     /**
1902      * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1903      * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1904      *
1905      * <pre>
1906      * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1907      * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1908      * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1909      * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1910      * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1911      * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1912      * </pre>
1913      *
1914      * @param string to compare, may be {@code null}.
1915      * @param searchStrings a vararg of strings, may be {@code null}.
1916      * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1917      * {@code false} if {@code searchStrings} is null or contains no matches.
1918      * @since 3.5
1919      */
1920     public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1921         if (ArrayUtils.isNotEmpty(searchStrings)) {
1922             for (final CharSequence next : searchStrings) {
1923                 if (equalsIgnoreCase(string, next)) {
1924                     return true;
1925                 }
1926             }
1927         }
1928         return false;
1929     }
1930 
1931     /**
1932      * Compares two CharSequences, returning {@code true} if they represent
1933      * equal sequences of characters, ignoring case.
1934      *
1935      * <p>{@code null}s are handled without exceptions. Two {@code null}
1936      * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
1937      *
1938      * <pre>
1939      * StringUtils.equalsIgnoreCase(null, null)   = true
1940      * StringUtils.equalsIgnoreCase(null, "abc")  = false
1941      * StringUtils.equalsIgnoreCase("abc", null)  = false
1942      * StringUtils.equalsIgnoreCase("abc", "abc") = true
1943      * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1944      * </pre>
1945      *
1946      * @param cs1  the first CharSequence, may be {@code null}
1947      * @param cs2  the second CharSequence, may be {@code null}
1948      * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
1949      * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1950      * @see #equals(CharSequence, CharSequence)
1951      */
1952     public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1953         if (cs1 == cs2) {
1954             return true;
1955         }
1956         if (cs1 == null || cs2 == null) {
1957             return false;
1958         }
1959         if (cs1.length() != cs2.length()) {
1960             return false;
1961         }
1962         return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
1963     }
1964 
1965     /**
1966      * Returns the first value in the array which is not empty (""),
1967      * {@code null} or whitespace only.
1968      *
1969      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1970      *
1971      * <p>If all values are blank or the array is {@code null}
1972      * or empty then {@code null} is returned.</p>
1973      *
1974      * <pre>
1975      * StringUtils.firstNonBlank(null, null, null)     = null
1976      * StringUtils.firstNonBlank(null, "", " ")        = null
1977      * StringUtils.firstNonBlank("abc")                = "abc"
1978      * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1979      * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1980      * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1981      * StringUtils.firstNonBlank()                     = null
1982      * </pre>
1983      *
1984      * @param <T> the specific kind of CharSequence
1985      * @param values  the values to test, may be {@code null} or empty
1986      * @return the first value from {@code values} which is not blank,
1987      *  or {@code null} if there are no non-blank values
1988      * @since 3.8
1989      */
1990     @SafeVarargs
1991     public static <T extends CharSequence> T firstNonBlank(final T... values) {
1992         if (values != null) {
1993             for (final T val : values) {
1994                 if (isNotBlank(val)) {
1995                     return val;
1996                 }
1997             }
1998         }
1999         return null;
2000     }
2001 
2002     /**
2003      * Returns the first value in the array which is not empty.
2004      *
2005      * <p>If all values are empty or the array is {@code null}
2006      * or empty then {@code null} is returned.</p>
2007      *
2008      * <pre>
2009      * StringUtils.firstNonEmpty(null, null, null)   = null
2010      * StringUtils.firstNonEmpty(null, null, "")     = null
2011      * StringUtils.firstNonEmpty(null, "", " ")      = " "
2012      * StringUtils.firstNonEmpty("abc")              = "abc"
2013      * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
2014      * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
2015      * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
2016      * StringUtils.firstNonEmpty()                   = null
2017      * </pre>
2018      *
2019      * @param <T> the specific kind of CharSequence
2020      * @param values  the values to test, may be {@code null} or empty
2021      * @return the first value from {@code values} which is not empty,
2022      *  or {@code null} if there are no non-empty values
2023      * @since 3.8
2024      */
2025     @SafeVarargs
2026     public static <T extends CharSequence> T firstNonEmpty(final T... values) {
2027         if (values != null) {
2028             for (final T val : values) {
2029                 if (isNotEmpty(val)) {
2030                     return val;
2031                 }
2032             }
2033         }
2034         return null;
2035     }
2036 
2037     /**
2038      * Calls {@link String#getBytes(Charset)} in a null-safe manner.
2039      *
2040      * @param string input string
2041      * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
2042      * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
2043      * @see String#getBytes(Charset)
2044      * @since 3.10
2045      */
2046     public static byte[] getBytes(final String string, final Charset charset) {
2047         return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
2048     }
2049 
2050     /**
2051      * Calls {@link String#getBytes(String)} in a null-safe manner.
2052      *
2053      * @param string input string
2054      * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
2055      * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
2056      * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
2057      * @see String#getBytes(String)
2058      * @since 3.10
2059      */
2060     public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
2061         return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
2062     }
2063 
2064     /**
2065      * Compares all Strings in an array and returns the initial sequence of
2066      * characters that is common to all of them.
2067      *
2068      * <p>For example,
2069      * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
2070      *
2071      * <pre>
2072      * StringUtils.getCommonPrefix(null)                             = ""
2073      * StringUtils.getCommonPrefix(new String[] {})                  = ""
2074      * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
2075      * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
2076      * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
2077      * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
2078      * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
2079      * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
2080      * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
2081      * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
2082      * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
2083      * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
2084      * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
2085      * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
2086      * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
2087      * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
2088      * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
2089      * </pre>
2090      *
2091      * @param strs  array of String objects, entries may be null
2092      * @return the initial sequence of characters that are common to all Strings
2093      * in the array; empty String if the array is null, the elements are all null
2094      * or if there is no common prefix.
2095      * @since 2.4
2096      */
2097     public static String getCommonPrefix(final String... strs) {
2098         if (ArrayUtils.isEmpty(strs)) {
2099             return EMPTY;
2100         }
2101         final int smallestIndexOfDiff = indexOfDifference(strs);
2102         if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2103             // all strings were identical
2104             if (strs[0] == null) {
2105                 return EMPTY;
2106             }
2107             return strs[0];
2108         }
2109         if (smallestIndexOfDiff == 0) {
2110             // there were no common initial characters
2111             return EMPTY;
2112         }
2113         // we found a common initial character sequence
2114         return strs[0].substring(0, smallestIndexOfDiff);
2115     }
2116 
2117     /**
2118      * Checks if a String {@code str} contains Unicode digits,
2119      * if yes then concatenate all the digits in {@code str} and return it as a String.
2120      *
2121      * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
2122      *
2123      * <pre>
2124      * StringUtils.getDigits(null)                 = null
2125      * StringUtils.getDigits("")                   = ""
2126      * StringUtils.getDigits("abc")                = ""
2127      * StringUtils.getDigits("1000$")              = "1000"
2128      * StringUtils.getDigits("1123~45")            = "112345"
2129      * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2130      * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2131      * </pre>
2132      *
2133      * @param str the String to extract digits from, may be null
2134      * @return String with only digits,
2135      *           or an empty ("") String if no digits found,
2136      *           or {@code null} String if {@code str} is null
2137      * @since 3.6
2138      */
2139     public static String getDigits(final String str) {
2140         if (isEmpty(str)) {
2141             return str;
2142         }
2143         final int sz = str.length();
2144         final StringBuilder strDigits = new StringBuilder(sz);
2145         for (int i = 0; i < sz; i++) {
2146             final char tempChar = str.charAt(i);
2147             if (Character.isDigit(tempChar)) {
2148                 strDigits.append(tempChar);
2149             }
2150         }
2151         return strDigits.toString();
2152     }
2153 
2154     /**
2155      * Find the Fuzzy Distance which indicates the similarity score between two Strings.
2156      *
2157      * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
2158      * TextMate, Atom and others. One point is given for every matched character. Subsequent
2159      * matches yield two bonus points. A higher score indicates a higher similarity.</p>
2160      *
2161      * <pre>
2162      * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2163      * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2164      * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2165      * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2166      * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2167      * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2168      * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2169      * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2170      * </pre>
2171      *
2172      * @param term a full term that should be matched against, must not be null
2173      * @param query the query that will be matched against a term, must not be null
2174      * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
2175      *  both Strings to lower case.
2176      * @return result score
2177      * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
2178      * @since 3.4
2179      * @deprecated As of 3.6, use Apache Commons Text
2180      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2181      * FuzzyScore</a> instead
2182      */
2183     @Deprecated
2184     public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2185         if (term == null || query == null) {
2186             throw new IllegalArgumentException("Strings must not be null");
2187         }
2188         if (locale == null) {
2189             throw new IllegalArgumentException("Locale must not be null");
2190         }
2191 
2192         // fuzzy logic is case-insensitive. We normalize the Strings to lower
2193         // case right from the start. Turning characters to lower case
2194         // via Character.toLowerCase(char) is unfortunately insufficient
2195         // as it does not accept a locale.
2196         final String termLowerCase = term.toString().toLowerCase(locale);
2197         final String queryLowerCase = query.toString().toLowerCase(locale);
2198 
2199         // the resulting score
2200         int score = 0;
2201 
2202         // the position in the term which will be scanned next for potential
2203         // query character matches
2204         int termIndex = 0;
2205 
2206         // index of the previously matched character in the term
2207         int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2208 
2209         for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2210             final char queryChar = queryLowerCase.charAt(queryIndex);
2211 
2212             boolean termCharacterMatchFound = false;
2213             for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2214                 final char termChar = termLowerCase.charAt(termIndex);
2215 
2216                 if (queryChar == termChar) {
2217                     // simple character matches result in one point
2218                     score++;
2219 
2220                     // subsequent character matches further improve
2221                     // the score.
2222                     if (previousMatchingCharacterIndex + 1 == termIndex) {
2223                         score += 2;
2224                     }
2225 
2226                     previousMatchingCharacterIndex = termIndex;
2227 
2228                     // we can leave the nested loop. Every character in the
2229                     // query can match at most one character in the term.
2230                     termCharacterMatchFound = true;
2231                 }
2232             }
2233         }
2234 
2235         return score;
2236     }
2237 
2238     /**
2239      * Returns either the passed in CharSequence, or if the CharSequence is
2240      * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.
2241      *
2242      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2243      *
2244      * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2245      *
2246      * <pre>
2247      * {@code
2248      * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2249      * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2250      * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2251      * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2252      * StringUtils.getIfBlank("", () -> null)       = null
2253      * StringUtils.getIfBlank("", null)             = null
2254      * }</pre>
2255      * @param <T> the specific kind of CharSequence
2256      * @param str the CharSequence to check, may be null
2257      * @param defaultSupplier the supplier of default CharSequence to return
2258      *  if the input is whitespace, empty ("") or {@code null}, may be null
2259      * @return the passed in CharSequence, or the default
2260      * @see StringUtils#defaultString(String, String)
2261      * @since 3.10
2262      */
2263     public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2264         return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2265     }
2266 
2267     /**
2268      * Returns either the passed in CharSequence, or if the CharSequence is
2269      * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2270      *
2271      * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2272      *
2273      * <pre>
2274      * {@code
2275      * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2276      * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2277      * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2278      * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2279      * StringUtils.getIfEmpty("", () -> null)        = null
2280      * StringUtils.getIfEmpty("", null)              = null
2281      * }
2282      * </pre>
2283      * @param <T> the specific kind of CharSequence
2284      * @param str  the CharSequence to check, may be null
2285      * @param defaultSupplier  the supplier of default CharSequence to return
2286      *  if the input is empty ("") or {@code null}, may be null
2287      * @return the passed in CharSequence, or the default
2288      * @see StringUtils#defaultString(String, String)
2289      * @since 3.10
2290      */
2291     public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2292         return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2293     }
2294 
2295     /**
2296      * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
2297      *
2298      * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
2299      * Winkler increased this measure for matching initial characters.</p>
2300      *
2301      * <p>This implementation is based on the Jaro Winkler similarity algorithm
2302      * 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>
2303      *
2304      * <pre>
2305      * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2306      * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2307      * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2308      * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2309      * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2310      * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2311      * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2312      * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2313      * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2314      * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2315      * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2316      * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2317      * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2318      * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2319      * </pre>
2320      *
2321      * @param first the first String, must not be null
2322      * @param second the second String, must not be null
2323      * @return result distance
2324      * @throws IllegalArgumentException if either String input {@code null}
2325      * @since 3.3
2326      * @deprecated As of 3.6, use Apache Commons Text
2327      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2328      * JaroWinklerDistance</a> instead
2329      */
2330     @Deprecated
2331     public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2332         final double DEFAULT_SCALING_FACTOR = 0.1;
2333 
2334         if (first == null || second == null) {
2335             throw new IllegalArgumentException("Strings must not be null");
2336         }
2337 
2338         final int[] mtp = matches(first, second);
2339         final double m = mtp[0];
2340         if (m == 0) {
2341             return 0D;
2342         }
2343         final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2344         final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2345         return Math.round(jw * 100.0D) / 100.0D;
2346     }
2347 
2348     /**
2349      * Find the Levenshtein distance between two Strings.
2350      *
2351      * <p>This is the number of changes needed to change one String into
2352      * another, where each change is a single character modification (deletion,
2353      * insertion or substitution).</p>
2354      *
2355      * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
2356      * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2357      * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
2358      *
2359      * <pre>
2360      * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2361      * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2362      * StringUtils.getLevenshteinDistance("", "")              = 0
2363      * StringUtils.getLevenshteinDistance("", "a")             = 1
2364      * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2365      * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2366      * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2367      * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2368      * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2369      * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2370      * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2371      * </pre>
2372      *
2373      * @param s  the first String, must not be null
2374      * @param t  the second String, must not be null
2375      * @return result distance
2376      * @throws IllegalArgumentException if either String input {@code null}
2377      * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
2378      * getLevenshteinDistance(CharSequence, CharSequence)
2379      * @deprecated As of 3.6, use Apache Commons Text
2380      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2381      * LevenshteinDistance</a> instead
2382      */
2383     @Deprecated
2384     public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2385         if (s == null || t == null) {
2386             throw new IllegalArgumentException("Strings must not be null");
2387         }
2388 
2389         int n = s.length();
2390         int m = t.length();
2391 
2392         if (n == 0) {
2393             return m;
2394         }
2395         if (m == 0) {
2396             return n;
2397         }
2398 
2399         if (n > m) {
2400             // swap the input strings to consume less memory
2401             final CharSequence tmp = s;
2402             s = t;
2403             t = tmp;
2404             n = m;
2405             m = t.length();
2406         }
2407 
2408         final int[] p = new int[n + 1];
2409         // indexes into strings s and t
2410         int i; // iterates through s
2411         int j; // iterates through t
2412         int upperleft;
2413         int upper;
2414 
2415         char jOfT; // jth character of t
2416         int cost;
2417 
2418         for (i = 0; i <= n; i++) {
2419             p[i] = i;
2420         }
2421 
2422         for (j = 1; j <= m; j++) {
2423             upperleft = p[0];
2424             jOfT = t.charAt(j - 1);
2425             p[0] = j;
2426 
2427             for (i = 1; i <= n; i++) {
2428                 upper = p[i];
2429                 cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2430                 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2431                 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2432                 upperleft = upper;
2433             }
2434         }
2435 
2436         return p[n];
2437     }
2438 
2439     /**
2440      * Find the Levenshtein distance between two Strings if it's less than or equal to a given
2441      * threshold.
2442      *
2443      * <p>This is the number of changes needed to change one String into
2444      * another, where each change is a single character modification (deletion,
2445      * insertion or substitution).</p>
2446      *
2447      * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
2448      * and Chas Emerick's implementation of the Levenshtein distance algorithm from
2449      * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
2450      *
2451      * <pre>
2452      * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2453      * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2454      * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2455      * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2456      * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2457      * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2458      * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2459      * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2460      * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2461      * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2462      * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2463      * </pre>
2464      *
2465      * @param s  the first String, must not be null
2466      * @param t  the second String, must not be null
2467      * @param threshold the target threshold, must not be negative
2468      * @return result distance, or {@code -1} if the distance would be greater than the threshold
2469      * @throws IllegalArgumentException if either String input {@code null} or negative threshold
2470      * @deprecated As of 3.6, use Apache Commons Text
2471      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2472      * LevenshteinDistance</a> instead
2473      */
2474     @Deprecated
2475     public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2476         if (s == null || t == null) {
2477             throw new IllegalArgumentException("Strings must not be null");
2478         }
2479         if (threshold < 0) {
2480             throw new IllegalArgumentException("Threshold must not be negative");
2481         }
2482 
2483         /*
2484         This implementation only computes the distance if it's less than or equal to the
2485         threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2486         distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2487         computing a diagonal stripe of width 2k + 1 of the cost table.
2488         It is also possible to use this to compute the unbounded Levenshtein distance by starting
2489         the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2490         d is the distance.
2491 
2492         One subtlety comes from needing to ignore entries on the border of our stripe
2493         eg.
2494         p[] = |#|#|#|*
2495         d[] =  *|#|#|#|
2496         We must ignore the entry to the left of the leftmost member
2497         We must ignore the entry above the rightmost member
2498 
2499         Another subtlety comes from our stripe running off the matrix if the strings aren't
2500         of the same size.  Since string s is always swapped to be the shorter of the two,
2501         the stripe will always run off to the upper right instead of the lower left of the matrix.
2502 
2503         As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2504         In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2505 
2506            1 2 3 4 5
2507         1 |#|#| | | |
2508         2 |#|#|#| | |
2509         3 | |#|#|#| |
2510         4 | | |#|#|#|
2511         5 | | | |#|#|
2512         6 | | | | |#|
2513         7 | | | | | |
2514 
2515         Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2516         into one of length 7 in edit distance of 1.
2517 
2518         Additionally, this implementation decreases memory usage by using two
2519         single-dimensional arrays and swapping them back and forth instead of allocating
2520         an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2521         when it's detected that the stripe has run off the matrix and initially filling the arrays with
2522         large values so that entries we don't compute are ignored.
2523 
2524         See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2525          */
2526 
2527         int n = s.length(); // length of s
2528         int m = t.length(); // length of t
2529 
2530         // if one string is empty, the edit distance is necessarily the length of the other
2531         if (n == 0) {
2532             return m <= threshold ? m : -1;
2533         }
2534         if (m == 0) {
2535             return n <= threshold ? n : -1;
2536         }
2537         if (Math.abs(n - m) > threshold) {
2538             // no need to calculate the distance if the length difference is greater than the threshold
2539             return -1;
2540         }
2541 
2542         if (n > m) {
2543             // swap the two strings to consume less memory
2544             final CharSequence tmp = s;
2545             s = t;
2546             t = tmp;
2547             n = m;
2548             m = t.length();
2549         }
2550 
2551         int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2552         int[] d = new int[n + 1]; // cost array, horizontally
2553         int[] tmp; // placeholder to assist in swapping p and d
2554 
2555         // fill in starting table values
2556         final int boundary = Math.min(n, threshold) + 1;
2557         for (int i = 0; i < boundary; i++) {
2558             p[i] = i;
2559         }
2560         // these fills ensure that the value above the rightmost entry of our
2561         // stripe will be ignored in following loop iterations
2562         Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2563         Arrays.fill(d, Integer.MAX_VALUE);
2564 
2565         // iterates through t
2566         for (int j = 1; j <= m; j++) {
2567             final char jOfT = t.charAt(j - 1); // jth character of t
2568             d[0] = j;
2569 
2570             // compute stripe indices, constrain to array size
2571             final int min = Math.max(1, j - threshold);
2572             final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2573 
2574             // the stripe may lead off of the table if s and t are of different sizes
2575             if (min > max) {
2576                 return -1;
2577             }
2578 
2579             // ignore entry left of leftmost
2580             if (min > 1) {
2581                 d[min - 1] = Integer.MAX_VALUE;
2582             }
2583 
2584             // iterates through [min, max] in s
2585             for (int i = min; i <= max; i++) {
2586                 if (s.charAt(i - 1) == jOfT) {
2587                     // diagonally left and up
2588                     d[i] = p[i - 1];
2589                 } else {
2590                     // 1 + minimum of cell to the left, to the top, diagonally left and up
2591                     d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2592                 }
2593             }
2594 
2595             // copy current distance counts to 'previous row' distance counts
2596             tmp = p;
2597             p = d;
2598             d = tmp;
2599         }
2600 
2601         // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2602         // distance
2603         if (p[n] <= threshold) {
2604             return p[n];
2605         }
2606         return -1;
2607     }
2608 
2609     /**
2610      * Finds the first index within a CharSequence, handling {@code null}.
2611      * This method uses {@link String#indexOf(String, int)} if possible.
2612      *
2613      * <p>A {@code null} CharSequence will return {@code -1}.</p>
2614      *
2615      * <pre>
2616      * StringUtils.indexOf(null, *)          = -1
2617      * StringUtils.indexOf(*, null)          = -1
2618      * StringUtils.indexOf("", "")           = 0
2619      * StringUtils.indexOf("", *)            = -1 (except when * = "")
2620      * StringUtils.indexOf("aabaabaa", "a")  = 0
2621      * StringUtils.indexOf("aabaabaa", "b")  = 2
2622      * StringUtils.indexOf("aabaabaa", "ab") = 1
2623      * StringUtils.indexOf("aabaabaa", "")   = 0
2624      * </pre>
2625      *
2626      * @param seq  the CharSequence to check, may be null
2627      * @param searchSeq  the CharSequence to find, may be null
2628      * @return the first index of the search CharSequence,
2629      *  -1 if no match or {@code null} string input
2630      * @since 2.0
2631      * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2632      */
2633     public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2634         if (seq == null || searchSeq == null) {
2635             return INDEX_NOT_FOUND;
2636         }
2637         return CharSequenceUtils.indexOf(seq, searchSeq, 0);
2638     }
2639 
2640     /**
2641      * Finds the first index within a CharSequence, handling {@code null}.
2642      * This method uses {@link String#indexOf(String, int)} if possible.
2643      *
2644      * <p>A {@code null} CharSequence will return {@code -1}.
2645      * A negative start position is treated as zero.
2646      * An empty ("") search CharSequence always matches.
2647      * A start position greater than the string length only matches
2648      * an empty search CharSequence.</p>
2649      *
2650      * <pre>
2651      * StringUtils.indexOf(null, *, *)          = -1
2652      * StringUtils.indexOf(*, null, *)          = -1
2653      * StringUtils.indexOf("", "", 0)           = 0
2654      * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2655      * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2656      * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2657      * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2658      * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2659      * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2660      * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2661      * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2662      * StringUtils.indexOf("abc", "", 9)        = 3
2663      * </pre>
2664      *
2665      * @param seq  the CharSequence to check, may be null
2666      * @param searchSeq  the CharSequence to find, may be null
2667      * @param startPos  the start position, negative treated as zero
2668      * @return the first index of the search CharSequence (always &ge; startPos),
2669      *  -1 if no match or {@code null} string input
2670      * @since 2.0
2671      * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2672      */
2673     public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2674         if (seq == null || searchSeq == null) {
2675             return INDEX_NOT_FOUND;
2676         }
2677         return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
2678     }
2679 
2680     /**
2681      * Returns the index within {@code seq} of the first occurrence of
2682      * the specified character. If a character with value
2683      * {@code searchChar} occurs in the character sequence represented by
2684      * {@code seq} {@link CharSequence} object, then the index (in Unicode
2685      * code units) of the first such occurrence is returned. For
2686      * values of {@code searchChar} in the range from 0 to 0xFFFF
2687      * (inclusive), this is the smallest value <em>k</em> such that:
2688      * <blockquote><pre>
2689      * this.charAt(<em>k</em>) == searchChar
2690      * </pre></blockquote>
2691      * is true. For other values of {@code searchChar}, it is the
2692      * smallest value <em>k</em> such that:
2693      * <blockquote><pre>
2694      * this.codePointAt(<em>k</em>) == searchChar
2695      * </pre></blockquote>
2696      * is true. In either case, if no such character occurs in {@code seq},
2697      * then {@code INDEX_NOT_FOUND (-1)} is returned.
2698      *
2699      * <p>Furthermore, a {@code null} or empty ("") CharSequence will
2700      * return {@code INDEX_NOT_FOUND (-1)}.</p>
2701      *
2702      * <pre>
2703      * StringUtils.indexOf(null, *)         = -1
2704      * StringUtils.indexOf("", *)           = -1
2705      * StringUtils.indexOf("aabaabaa", 'a') = 0
2706      * StringUtils.indexOf("aabaabaa", 'b') = 2
2707      * </pre>
2708      *
2709      * @param seq  the CharSequence to check, may be null
2710      * @param searchChar  the character to find
2711      * @return the first index of the search character,
2712      *  -1 if no match or {@code null} string input
2713      * @since 2.0
2714      * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, 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) {
2718         if (isEmpty(seq)) {
2719             return INDEX_NOT_FOUND;
2720         }
2721         return CharSequenceUtils.indexOf(seq, searchChar, 0);
2722     }
2723 
2724     /**
2725      * Returns the index within {@code seq} of the first occurrence of the
2726      * specified character, starting the search at the specified index.
2727      * <p>
2728      * If a character with value {@code searchChar} occurs in the
2729      * character sequence represented by the {@code seq} {@link CharSequence}
2730      * object at an index no smaller than {@code startPos}, then
2731      * the index of the first such occurrence is returned. For values
2732      * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
2733      * this is the smallest value <em>k</em> such that:
2734      * <blockquote><pre>
2735      * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2736      * </pre></blockquote>
2737      * is true. For other values of {@code searchChar}, it is the
2738      * smallest value <em>k</em> such that:
2739      * <blockquote><pre>
2740      * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2741      * </pre></blockquote>
2742      * is true. In either case, if no such character occurs in {@code seq}
2743      * at or after position {@code startPos}, then
2744      * {@code -1} is returned.
2745      *
2746      * <p>
2747      * There is no restriction on the value of {@code startPos}. If it
2748      * is negative, it has the same effect as if it were zero: this entire
2749      * string may be searched. If it is greater than the length of this
2750      * string, it has the same effect as if it were equal to the length of
2751      * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
2752      * {@code null} or empty ("") CharSequence will
2753      * return {@code (INDEX_NOT_FOUND) -1}.
2754      *
2755      * <p>All indices are specified in {@code char} values
2756      * (Unicode code units).
2757      *
2758      * <pre>
2759      * StringUtils.indexOf(null, *, *)          = -1
2760      * StringUtils.indexOf("", *, *)            = -1
2761      * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2762      * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2763      * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2764      * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2765      * </pre>
2766      *
2767      * @param seq  the CharSequence to check, may be null
2768      * @param searchChar  the character to find
2769      * @param startPos  the start position, negative treated as zero
2770      * @return the first index of the search character (always &ge; startPos),
2771      *  -1 if no match or {@code null} string input
2772      * @since 2.0
2773      * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2774      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2775      */
2776     public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2777         if (isEmpty(seq)) {
2778             return INDEX_NOT_FOUND;
2779         }
2780         return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2781     }
2782 
2783     /**
2784      * Search a CharSequence to find the first index of any
2785      * character in the given set of characters.
2786      *
2787      * <p>A {@code null} String will return {@code -1}.
2788      * A {@code null} or zero length search array will return {@code -1}.</p>
2789      *
2790      * <pre>
2791      * StringUtils.indexOfAny(null, *)                  = -1
2792      * StringUtils.indexOfAny("", *)                    = -1
2793      * StringUtils.indexOfAny(*, null)                  = -1
2794      * StringUtils.indexOfAny(*, [])                    = -1
2795      * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2796      * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2797      * StringUtils.indexOfAny("aba", ['z'])             = -1
2798      * </pre>
2799      *
2800      * @param cs  the CharSequence to check, may be null
2801      * @param searchChars  the chars to search for, may be null
2802      * @return the index of any of the chars, -1 if no match or null input
2803      * @since 2.0
2804      * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2805      */
2806     public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2807         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2808             return INDEX_NOT_FOUND;
2809         }
2810         final int csLen = cs.length();
2811         final int csLast = csLen - 1;
2812         final int searchLen = searchChars.length;
2813         final int searchLast = searchLen - 1;
2814         for (int i = 0; i < csLen; i++) {
2815             final char ch = cs.charAt(i);
2816             for (int j = 0; j < searchLen; j++) {
2817                 if (searchChars[j] == ch) {
2818                     if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
2819                         return i;
2820                     }
2821                     // ch is a supplementary character
2822                     if (searchChars[j + 1] == cs.charAt(i + 1)) {
2823                         return i;
2824                     }
2825                 }
2826             }
2827         }
2828         return INDEX_NOT_FOUND;
2829     }
2830 
2831     /**
2832      * Find the first index of any of a set of potential substrings.
2833      *
2834      * <p>A {@code null} CharSequence will return {@code -1}.
2835      * A {@code null} or zero length search array will return {@code -1}.
2836      * A {@code null} search array entry will be ignored, but a search
2837      * array containing "" will return {@code 0} if {@code str} is not
2838      * null. This method uses {@link String#indexOf(String)} if possible.</p>
2839      *
2840      * <pre>
2841      * StringUtils.indexOfAny(null, *)                      = -1
2842      * StringUtils.indexOfAny(*, null)                      = -1
2843      * StringUtils.indexOfAny(*, [])                        = -1
2844      * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2845      * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2846      * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2847      * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2848      * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2849      * StringUtils.indexOfAny("", [""])                     = 0
2850      * StringUtils.indexOfAny("", ["a"])                    = -1
2851      * </pre>
2852      *
2853      * @param str  the CharSequence to check, may be null
2854      * @param searchStrs  the CharSequences to search for, may be null
2855      * @return the first index of any of the searchStrs in str, -1 if no match
2856      * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2857      */
2858     public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2859         if (str == null || searchStrs == null) {
2860             return INDEX_NOT_FOUND;
2861         }
2862 
2863         // String's can't have a MAX_VALUEth index.
2864         int ret = Integer.MAX_VALUE;
2865 
2866         int tmp;
2867         for (final CharSequence search : searchStrs) {
2868             if (search == null) {
2869                 continue;
2870             }
2871             tmp = CharSequenceUtils.indexOf(str, search, 0);
2872             if (tmp == INDEX_NOT_FOUND) {
2873                 continue;
2874             }
2875 
2876             if (tmp < ret) {
2877                 ret = tmp;
2878             }
2879         }
2880 
2881         return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2882     }
2883 
2884     /**
2885      * Search a CharSequence to find the first index of any
2886      * character in the given set of characters.
2887      *
2888      * <p>A {@code null} String will return {@code -1}.
2889      * A {@code null} search string will return {@code -1}.</p>
2890      *
2891      * <pre>
2892      * StringUtils.indexOfAny(null, *)            = -1
2893      * StringUtils.indexOfAny("", *)              = -1
2894      * StringUtils.indexOfAny(*, null)            = -1
2895      * StringUtils.indexOfAny(*, "")              = -1
2896      * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2897      * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2898      * StringUtils.indexOfAny("aba", "z")         = -1
2899      * </pre>
2900      *
2901      * @param cs  the CharSequence to check, may be null
2902      * @param searchChars  the chars to search for, may be null
2903      * @return the index of any of the chars, -1 if no match or null input
2904      * @since 2.0
2905      * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2906      */
2907     public static int indexOfAny(final CharSequence cs, final String searchChars) {
2908         if (isEmpty(cs) || isEmpty(searchChars)) {
2909             return INDEX_NOT_FOUND;
2910         }
2911         return indexOfAny(cs, searchChars.toCharArray());
2912     }
2913 
2914     /**
2915      * Searches a CharSequence to find the first index of any
2916      * character not in the given set of characters.
2917      *
2918      * <p>A {@code null} CharSequence will return {@code -1}.
2919      * A {@code null} or zero length search array will return {@code -1}.</p>
2920      *
2921      * <pre>
2922      * StringUtils.indexOfAnyBut(null, *)                              = -1
2923      * StringUtils.indexOfAnyBut("", *)                                = -1
2924      * StringUtils.indexOfAnyBut(*, null)                              = -1
2925      * StringUtils.indexOfAnyBut(*, [])                                = -1
2926      * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2927      * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2928      * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2929 
2930      * </pre>
2931      *
2932      * @param cs  the CharSequence to check, may be null
2933      * @param searchChars  the chars to search for, may be null
2934      * @return the index of any of the chars, -1 if no match or null input
2935      * @since 2.0
2936      * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2937      */
2938     public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2939         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2940             return INDEX_NOT_FOUND;
2941         }
2942         final int csLen = cs.length();
2943         final int csLast = csLen - 1;
2944         final int searchLen = searchChars.length;
2945         final int searchLast = searchLen - 1;
2946         outer:
2947         for (int i = 0; i < csLen; i++) {
2948             final char ch = cs.charAt(i);
2949             for (int j = 0; j < searchLen; j++) {
2950                 if (searchChars[j] == ch) {
2951                     if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
2952                         continue outer;
2953                     }
2954                     if (searchChars[j + 1] == cs.charAt(i + 1)) {
2955                         continue outer;
2956                     }
2957                 }
2958             }
2959             return i;
2960         }
2961         return INDEX_NOT_FOUND;
2962     }
2963 
2964     /**
2965      * Search a CharSequence to find the first index of any
2966      * character not in the given set of characters.
2967      *
2968      * <p>A {@code null} CharSequence will return {@code -1}.
2969      * A {@code null} or empty search string will return {@code -1}.</p>
2970      *
2971      * <pre>
2972      * StringUtils.indexOfAnyBut(null, *)            = -1
2973      * StringUtils.indexOfAnyBut("", *)              = -1
2974      * StringUtils.indexOfAnyBut(*, null)            = -1
2975      * StringUtils.indexOfAnyBut(*, "")              = -1
2976      * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2977      * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2978      * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2979      * </pre>
2980      *
2981      * @param seq  the CharSequence to check, may be null
2982      * @param searchChars  the chars to search for, may be null
2983      * @return the index of any of the chars, -1 if no match or null input
2984      * @since 2.0
2985      * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2986      */
2987     public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2988         if (isEmpty(seq) || isEmpty(searchChars)) {
2989             return INDEX_NOT_FOUND;
2990         }
2991         final int strLen = seq.length();
2992         for (int i = 0; i < strLen; i++) {
2993             final char ch = seq.charAt(i);
2994             final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2995             if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2996                 final char ch2 = seq.charAt(i + 1);
2997                 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2998                     return i;
2999                 }
3000             } else if (!chFound) {
3001                 return i;
3002             }
3003         }
3004         return INDEX_NOT_FOUND;
3005     }
3006 
3007     /**
3008      * Compares all CharSequences in an array and returns the index at which the
3009      * CharSequences begin to differ.
3010      *
3011      * <p>For example,
3012      * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
3013      *
3014      * <pre>
3015      * StringUtils.indexOfDifference(null)                             = -1
3016      * StringUtils.indexOfDifference(new String[] {})                  = -1
3017      * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
3018      * StringUtils.indexOfDifference(new String[] {null, null})        = -1
3019      * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
3020      * StringUtils.indexOfDifference(new String[] {"", null})          = 0
3021      * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
3022      * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
3023      * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
3024      * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
3025      * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
3026      * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
3027      * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
3028      * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
3029      * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
3030      * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
3031      * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
3032      * </pre>
3033      *
3034      * @param css  array of CharSequences, entries may be null
3035      * @return the index where the strings begin to differ; -1 if they are all equal
3036      * @since 2.4
3037      * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
3038      */
3039     public static int indexOfDifference(final CharSequence... css) {
3040         if (ArrayUtils.getLength(css) <= 1) {
3041             return INDEX_NOT_FOUND;
3042         }
3043         boolean anyStringNull = false;
3044         boolean allStringsNull = true;
3045         final int arrayLen = css.length;
3046         int shortestStrLen = Integer.MAX_VALUE;
3047         int longestStrLen = 0;
3048 
3049         // find the min and max string lengths; this avoids checking to make
3050         // sure we are not exceeding the length of the string each time through
3051         // the bottom loop.
3052         for (final CharSequence cs : css) {
3053             if (cs == null) {
3054                 anyStringNull = true;
3055                 shortestStrLen = 0;
3056             } else {
3057                 allStringsNull = false;
3058                 shortestStrLen = Math.min(cs.length(), shortestStrLen);
3059                 longestStrLen = Math.max(cs.length(), longestStrLen);
3060             }
3061         }
3062 
3063         // handle lists containing all nulls or all empty strings
3064         if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
3065             return INDEX_NOT_FOUND;
3066         }
3067 
3068         // handle lists containing some nulls or some empty strings
3069         if (shortestStrLen == 0) {
3070             return 0;
3071         }
3072 
3073         // find the position with the first difference across all strings
3074         int firstDiff = -1;
3075         for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
3076             final char comparisonChar = css[0].charAt(stringPos);
3077             for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
3078                 if (css[arrayPos].charAt(stringPos) != comparisonChar) {
3079                     firstDiff = stringPos;
3080                     break;
3081                 }
3082             }
3083             if (firstDiff != -1) {
3084                 break;
3085             }
3086         }
3087 
3088         if (firstDiff == -1 && shortestStrLen != longestStrLen) {
3089             // we compared all of the characters up to the length of the
3090             // shortest string and didn't find a match, but the string lengths
3091             // vary, so return the length of the shortest string.
3092             return shortestStrLen;
3093         }
3094         return firstDiff;
3095     }
3096 
3097     /**
3098      * Compares two CharSequences, and returns the index at which the
3099      * CharSequences begin to differ.
3100      *
3101      * <p>For example,
3102      * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
3103      *
3104      * <pre>
3105      * StringUtils.indexOfDifference(null, null)       = -1
3106      * StringUtils.indexOfDifference("", "")           = -1
3107      * StringUtils.indexOfDifference("", "abc")        = 0
3108      * StringUtils.indexOfDifference("abc", "")        = 0
3109      * StringUtils.indexOfDifference("abc", "abc")     = -1
3110      * StringUtils.indexOfDifference("ab", "abxyz")    = 2
3111      * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3112      * StringUtils.indexOfDifference("abcde", "xyz")   = 0
3113      * </pre>
3114      *
3115      * @param cs1  the first CharSequence, may be null
3116      * @param cs2  the second CharSequence, may be null
3117      * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
3118      * @since 2.0
3119      * @since 3.0 Changed signature from indexOfDifference(String, String) to
3120      * indexOfDifference(CharSequence, CharSequence)
3121      */
3122     public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3123         if (cs1 == cs2) {
3124             return INDEX_NOT_FOUND;
3125         }
3126         if (cs1 == null || cs2 == null) {
3127             return 0;
3128         }
3129         int i;
3130         for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3131             if (cs1.charAt(i) != cs2.charAt(i)) {
3132                 break;
3133             }
3134         }
3135         if (i < cs2.length() || i < cs1.length()) {
3136             return i;
3137         }
3138         return INDEX_NOT_FOUND;
3139     }
3140 
3141     /**
3142      * Case in-sensitive find of the first index within a CharSequence.
3143      *
3144      * <p>A {@code null} CharSequence will return {@code -1}.
3145      * A negative start position is treated as zero.
3146      * An empty ("") search CharSequence always matches.
3147      * A start position greater than the string length only matches
3148      * an empty search CharSequence.</p>
3149      *
3150      * <pre>
3151      * StringUtils.indexOfIgnoreCase(null, *)          = -1
3152      * StringUtils.indexOfIgnoreCase(*, null)          = -1
3153      * StringUtils.indexOfIgnoreCase("", "")           = 0
3154      * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3155      * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3156      * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3157      * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3158      * </pre>
3159      *
3160      * @param str  the CharSequence to check, may be null
3161      * @param searchStr  the CharSequence to find, may be null
3162      * @return the first index of the search CharSequence,
3163      *  -1 if no match or {@code null} string input
3164      * @since 2.5
3165      * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3166      */
3167     public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3168         return indexOfIgnoreCase(str, searchStr, 0);
3169     }
3170 
3171     /**
3172      * Case in-sensitive find of the first index within a CharSequence
3173      * from the specified position.
3174      *
3175      * <p>A {@code null} CharSequence will return {@code -1}.
3176      * A negative start position is treated as zero.
3177      * An empty ("") search CharSequence always matches.
3178      * A start position greater than the string length only matches
3179      * an empty search CharSequence.</p>
3180      *
3181      * <pre>
3182      * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3183      * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3184      * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3185      * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3186      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3187      * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3188      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3189      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3190      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3191      * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3192      * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3193      * </pre>
3194      *
3195      * @param str  the CharSequence to check, may be null
3196      * @param searchStr  the CharSequence to find, may be null
3197      * @param startPos  the start position, negative treated as zero
3198      * @return the first index of the search CharSequence (always &ge; startPos),
3199      *  -1 if no match or {@code null} string input
3200      * @since 2.5
3201      * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3202      */
3203     public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
3204         if (str == null || searchStr == null) {
3205             return INDEX_NOT_FOUND;
3206         }
3207         if (startPos < 0) {
3208             startPos = 0;
3209         }
3210         final int endLimit = str.length() - searchStr.length() + 1;
3211         if (startPos > endLimit) {
3212             return INDEX_NOT_FOUND;
3213         }
3214         if (searchStr.length() == 0) {
3215             return startPos;
3216         }
3217         for (int i = startPos; i < endLimit; i++) {
3218             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
3219                 return i;
3220             }
3221         }
3222         return INDEX_NOT_FOUND;
3223     }
3224 
3225     /**
3226      * Checks if all of the CharSequences are empty (""), null or whitespace only.
3227      *
3228      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3229      *
3230      * <pre>
3231      * StringUtils.isAllBlank(null)             = true
3232      * StringUtils.isAllBlank(null, "foo")      = false
3233      * StringUtils.isAllBlank(null, null)       = true
3234      * StringUtils.isAllBlank("", "bar")        = false
3235      * StringUtils.isAllBlank("bob", "")        = false
3236      * StringUtils.isAllBlank("  bob  ", null)  = false
3237      * StringUtils.isAllBlank(" ", "bar")       = false
3238      * StringUtils.isAllBlank("foo", "bar")     = false
3239      * StringUtils.isAllBlank(new String[] {})  = true
3240      * </pre>
3241      *
3242      * @param css  the CharSequences to check, may be null or empty
3243      * @return {@code true} if all of the CharSequences are empty or null or whitespace only
3244      * @since 3.6
3245      */
3246     public static boolean isAllBlank(final CharSequence... css) {
3247         if (ArrayUtils.isEmpty(css)) {
3248             return true;
3249         }
3250         for (final CharSequence cs : css) {
3251             if (isNotBlank(cs)) {
3252                return false;
3253             }
3254         }
3255         return true;
3256     }
3257 
3258     /**
3259      * Checks if all of the CharSequences are empty ("") or null.
3260      *
3261      * <pre>
3262      * StringUtils.isAllEmpty(null)             = true
3263      * StringUtils.isAllEmpty(null, "")         = true
3264      * StringUtils.isAllEmpty(new String[] {})  = true
3265      * StringUtils.isAllEmpty(null, "foo")      = false
3266      * StringUtils.isAllEmpty("", "bar")        = false
3267      * StringUtils.isAllEmpty("bob", "")        = false
3268      * StringUtils.isAllEmpty("  bob  ", null)  = false
3269      * StringUtils.isAllEmpty(" ", "bar")       = false
3270      * StringUtils.isAllEmpty("foo", "bar")     = false
3271      * </pre>
3272      *
3273      * @param css  the CharSequences to check, may be null or empty
3274      * @return {@code true} if all of the CharSequences are empty or null
3275      * @since 3.6
3276      */
3277     public static boolean isAllEmpty(final CharSequence... css) {
3278         if (ArrayUtils.isEmpty(css)) {
3279             return true;
3280         }
3281         for (final CharSequence cs : css) {
3282             if (isNotEmpty(cs)) {
3283                 return false;
3284             }
3285         }
3286         return true;
3287     }
3288 
3289     /**
3290      * Checks if the CharSequence contains only lowercase characters.
3291      *
3292      * <p>{@code null} will return {@code false}.
3293      * An empty CharSequence (length()=0) will return {@code false}.</p>
3294      *
3295      * <pre>
3296      * StringUtils.isAllLowerCase(null)   = false
3297      * StringUtils.isAllLowerCase("")     = false
3298      * StringUtils.isAllLowerCase("  ")   = false
3299      * StringUtils.isAllLowerCase("abc")  = true
3300      * StringUtils.isAllLowerCase("abC")  = false
3301      * StringUtils.isAllLowerCase("ab c") = false
3302      * StringUtils.isAllLowerCase("ab1c") = false
3303      * StringUtils.isAllLowerCase("ab/c") = false
3304      * </pre>
3305      *
3306      * @param cs  the CharSequence to check, may be null
3307      * @return {@code true} if only contains lowercase characters, and is non-null
3308      * @since 2.5
3309      * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3310      */
3311     public static boolean isAllLowerCase(final CharSequence cs) {
3312         if (isEmpty(cs)) {
3313             return false;
3314         }
3315         final int sz = cs.length();
3316         for (int i = 0; i < sz; i++) {
3317             if (!Character.isLowerCase(cs.charAt(i))) {
3318                 return false;
3319             }
3320         }
3321         return true;
3322     }
3323 
3324     /**
3325      * Checks if the CharSequence contains only uppercase characters.
3326      *
3327      * <p>{@code null} will return {@code false}.
3328      * An empty String (length()=0) will return {@code false}.</p>
3329      *
3330      * <pre>
3331      * StringUtils.isAllUpperCase(null)   = false
3332      * StringUtils.isAllUpperCase("")     = false
3333      * StringUtils.isAllUpperCase("  ")   = false
3334      * StringUtils.isAllUpperCase("ABC")  = true
3335      * StringUtils.isAllUpperCase("aBC")  = false
3336      * StringUtils.isAllUpperCase("A C")  = false
3337      * StringUtils.isAllUpperCase("A1C")  = false
3338      * StringUtils.isAllUpperCase("A/C")  = false
3339      * </pre>
3340      *
3341      * @param cs the CharSequence to check, may be null
3342      * @return {@code true} if only contains uppercase characters, and is non-null
3343      * @since 2.5
3344      * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3345      */
3346     public static boolean isAllUpperCase(final CharSequence cs) {
3347         if (isEmpty(cs)) {
3348             return false;
3349         }
3350         final int sz = cs.length();
3351         for (int i = 0; i < sz; i++) {
3352             if (!Character.isUpperCase(cs.charAt(i))) {
3353                 return false;
3354             }
3355         }
3356         return true;
3357     }
3358 
3359     /**
3360      * Checks if the CharSequence contains only Unicode letters.
3361      *
3362      * <p>{@code null} will return {@code false}.
3363      * An empty CharSequence (length()=0) will return {@code false}.</p>
3364      *
3365      * <pre>
3366      * StringUtils.isAlpha(null)   = false
3367      * StringUtils.isAlpha("")     = false
3368      * StringUtils.isAlpha("  ")   = false
3369      * StringUtils.isAlpha("abc")  = true
3370      * StringUtils.isAlpha("ab2c") = false
3371      * StringUtils.isAlpha("ab-c") = false
3372      * </pre>
3373      *
3374      * @param cs  the CharSequence to check, may be null
3375      * @return {@code true} if only contains letters, and is non-null
3376      * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3377      * @since 3.0 Changed "" to return false and not true
3378      */
3379     public static boolean isAlpha(final CharSequence cs) {
3380         if (isEmpty(cs)) {
3381             return false;
3382         }
3383         final int sz = cs.length();
3384         for (int i = 0; i < sz; i++) {
3385             if (!Character.isLetter(cs.charAt(i))) {
3386                 return false;
3387             }
3388         }
3389         return true;
3390     }
3391 
3392     /**
3393      * Checks if the CharSequence contains only Unicode letters or digits.
3394      *
3395      * <p>{@code null} will return {@code false}.
3396      * An empty CharSequence (length()=0) will return {@code false}.</p>
3397      *
3398      * <pre>
3399      * StringUtils.isAlphanumeric(null)   = false
3400      * StringUtils.isAlphanumeric("")     = false
3401      * StringUtils.isAlphanumeric("  ")   = false
3402      * StringUtils.isAlphanumeric("abc")  = true
3403      * StringUtils.isAlphanumeric("ab c") = false
3404      * StringUtils.isAlphanumeric("ab2c") = true
3405      * StringUtils.isAlphanumeric("ab-c") = false
3406      * </pre>
3407      *
3408      * @param cs  the CharSequence to check, may be null
3409      * @return {@code true} if only contains letters or digits,
3410      *  and is non-null
3411      * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3412      * @since 3.0 Changed "" to return false and not true
3413      */
3414     public static boolean isAlphanumeric(final CharSequence cs) {
3415         if (isEmpty(cs)) {
3416             return false;
3417         }
3418         final int sz = cs.length();
3419         for (int i = 0; i < sz; i++) {
3420             if (!Character.isLetterOrDigit(cs.charAt(i))) {
3421                 return false;
3422             }
3423         }
3424         return true;
3425     }
3426 
3427     /**
3428      * Checks if the CharSequence contains only Unicode letters, digits
3429      * or space ({@code ' '}).
3430      *
3431      * <p>{@code null} will return {@code false}.
3432      * An empty CharSequence (length()=0) will return {@code true}.</p>
3433      *
3434      * <pre>
3435      * StringUtils.isAlphanumericSpace(null)   = false
3436      * StringUtils.isAlphanumericSpace("")     = true
3437      * StringUtils.isAlphanumericSpace("  ")   = true
3438      * StringUtils.isAlphanumericSpace("abc")  = true
3439      * StringUtils.isAlphanumericSpace("ab c") = true
3440      * StringUtils.isAlphanumericSpace("ab2c") = true
3441      * StringUtils.isAlphanumericSpace("ab-c") = false
3442      * </pre>
3443      *
3444      * @param cs  the CharSequence to check, may be null
3445      * @return {@code true} if only contains letters, digits or space,
3446      *  and is non-null
3447      * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3448      */
3449     public static boolean isAlphanumericSpace(final CharSequence cs) {
3450         if (cs == null) {
3451             return false;
3452         }
3453         final int sz = cs.length();
3454         for (int i = 0; i < sz; i++) {
3455             final char nowChar = cs.charAt(i);
3456             if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) {
3457                 return false;
3458             }
3459         }
3460         return true;
3461     }
3462 
3463     /**
3464      * Checks if the CharSequence contains only Unicode letters and
3465      * space (' ').
3466      *
3467      * <p>{@code null} will return {@code false}
3468      * An empty CharSequence (length()=0) will return {@code true}.</p>
3469      *
3470      * <pre>
3471      * StringUtils.isAlphaSpace(null)   = false
3472      * StringUtils.isAlphaSpace("")     = true
3473      * StringUtils.isAlphaSpace("  ")   = true
3474      * StringUtils.isAlphaSpace("abc")  = true
3475      * StringUtils.isAlphaSpace("ab c") = true
3476      * StringUtils.isAlphaSpace("ab2c") = false
3477      * StringUtils.isAlphaSpace("ab-c") = false
3478      * </pre>
3479      *
3480      * @param cs  the CharSequence to check, may be null
3481      * @return {@code true} if only contains letters and space,
3482      *  and is non-null
3483      * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3484      */
3485     public static boolean isAlphaSpace(final CharSequence cs) {
3486         if (cs == null) {
3487             return false;
3488         }
3489         final int sz = cs.length();
3490         for (int i = 0; i < sz; i++) {
3491             final char nowChar = cs.charAt(i);
3492             if (nowChar != ' ' && !Character.isLetter(nowChar)) {
3493                 return false;
3494             }
3495         }
3496         return true;
3497     }
3498 
3499     /**
3500      * Checks if any of the CharSequences are empty ("") or null or whitespace only.
3501      *
3502      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3503      *
3504      * <pre>
3505      * StringUtils.isAnyBlank((String) null)    = true
3506      * StringUtils.isAnyBlank((String[]) null)  = false
3507      * StringUtils.isAnyBlank(null, "foo")      = true
3508      * StringUtils.isAnyBlank(null, null)       = true
3509      * StringUtils.isAnyBlank("", "bar")        = true
3510      * StringUtils.isAnyBlank("bob", "")        = true
3511      * StringUtils.isAnyBlank("  bob  ", null)  = true
3512      * StringUtils.isAnyBlank(" ", "bar")       = true
3513      * StringUtils.isAnyBlank(new String[] {})  = false
3514      * StringUtils.isAnyBlank(new String[]{""}) = true
3515      * StringUtils.isAnyBlank("foo", "bar")     = false
3516      * </pre>
3517      *
3518      * @param css  the CharSequences to check, may be null or empty
3519      * @return {@code true} if any of the CharSequences are empty or null or whitespace only
3520      * @since 3.2
3521      */
3522     public static boolean isAnyBlank(final CharSequence... css) {
3523         if (ArrayUtils.isEmpty(css)) {
3524             return false;
3525         }
3526         for (final CharSequence cs : css) {
3527             if (isBlank(cs)) {
3528                 return true;
3529             }
3530         }
3531         return false;
3532     }
3533 
3534     /**
3535      * Checks if any of the CharSequences are empty ("") or null.
3536      *
3537      * <pre>
3538      * StringUtils.isAnyEmpty((String) null)    = true
3539      * StringUtils.isAnyEmpty((String[]) null)  = false
3540      * StringUtils.isAnyEmpty(null, "foo")      = true
3541      * StringUtils.isAnyEmpty("", "bar")        = true
3542      * StringUtils.isAnyEmpty("bob", "")        = true
3543      * StringUtils.isAnyEmpty("  bob  ", null)  = true
3544      * StringUtils.isAnyEmpty(" ", "bar")       = false
3545      * StringUtils.isAnyEmpty("foo", "bar")     = false
3546      * StringUtils.isAnyEmpty(new String[]{})   = false
3547      * StringUtils.isAnyEmpty(new String[]{""}) = true
3548      * </pre>
3549      *
3550      * @param css  the CharSequences to check, may be null or empty
3551      * @return {@code true} if any of the CharSequences are empty or null
3552      * @since 3.2
3553      */
3554     public static boolean isAnyEmpty(final CharSequence... css) {
3555         if (ArrayUtils.isEmpty(css)) {
3556             return false;
3557         }
3558         for (final CharSequence cs : css) {
3559             if (isEmpty(cs)) {
3560                 return true;
3561             }
3562         }
3563         return false;
3564     }
3565 
3566     /**
3567      * Checks if the CharSequence contains only ASCII printable characters.
3568      *
3569      * <p>{@code null} will return {@code false}.
3570      * An empty CharSequence (length()=0) will return {@code true}.</p>
3571      *
3572      * <pre>
3573      * StringUtils.isAsciiPrintable(null)     = false
3574      * StringUtils.isAsciiPrintable("")       = true
3575      * StringUtils.isAsciiPrintable(" ")      = true
3576      * StringUtils.isAsciiPrintable("Ceki")   = true
3577      * StringUtils.isAsciiPrintable("ab2c")   = true
3578      * StringUtils.isAsciiPrintable("!ab-c~") = true
3579      * StringUtils.isAsciiPrintable("\u0020") = true
3580      * StringUtils.isAsciiPrintable("\u0021") = true
3581      * StringUtils.isAsciiPrintable("\u007e") = true
3582      * StringUtils.isAsciiPrintable("\u007f") = false
3583      * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3584      * </pre>
3585      *
3586      * @param cs the CharSequence to check, may be null
3587      * @return {@code true} if every character is in the range
3588      *  32 through 126
3589      * @since 2.1
3590      * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3591      */
3592     public static boolean isAsciiPrintable(final CharSequence cs) {
3593         if (cs == null) {
3594             return false;
3595         }
3596         final int sz = cs.length();
3597         for (int i = 0; i < sz; i++) {
3598             if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3599                 return false;
3600             }
3601         }
3602         return true;
3603     }
3604 
3605     /**
3606      * Checks if a CharSequence is empty (""), null or whitespace only.
3607      *
3608      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3609      *
3610      * <pre>
3611      * StringUtils.isBlank(null)      = true
3612      * StringUtils.isBlank("")        = true
3613      * StringUtils.isBlank(" ")       = true
3614      * StringUtils.isBlank("bob")     = false
3615      * StringUtils.isBlank("  bob  ") = false
3616      * </pre>
3617      *
3618      * @param cs  the CharSequence to check, may be null
3619      * @return {@code true} if the CharSequence is null, empty or whitespace only
3620      * @since 2.0
3621      * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3622      */
3623     public static boolean isBlank(final CharSequence cs) {
3624         final int strLen = length(cs);
3625         if (strLen == 0) {
3626             return true;
3627         }
3628         for (int i = 0; i < strLen; i++) {
3629             if (!Character.isWhitespace(cs.charAt(i))) {
3630                 return false;
3631             }
3632         }
3633         return true;
3634     }
3635 
3636     /**
3637      * Checks if a CharSequence is empty ("") or null.
3638      *
3639      * <pre>
3640      * StringUtils.isEmpty(null)      = true
3641      * StringUtils.isEmpty("")        = true
3642      * StringUtils.isEmpty(" ")       = false
3643      * StringUtils.isEmpty("bob")     = false
3644      * StringUtils.isEmpty("  bob  ") = false
3645      * </pre>
3646      *
3647      * <p>NOTE: This method changed in Lang version 2.0.
3648      * It no longer trims the CharSequence.
3649      * That functionality is available in isBlank().</p>
3650      *
3651      * @param cs  the CharSequence to check, may be null
3652      * @return {@code true} if the CharSequence is empty or null
3653      * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3654      */
3655     public static boolean isEmpty(final CharSequence cs) {
3656         return cs == null || cs.length() == 0;
3657     }
3658 
3659     /**
3660      * Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3661      *
3662      * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
3663      * {@code false}.</p>
3664      *
3665      * <pre>
3666      * StringUtils.isMixedCase(null)    = false
3667      * StringUtils.isMixedCase("")      = false
3668      * StringUtils.isMixedCase(" ")     = false
3669      * StringUtils.isMixedCase("ABC")   = false
3670      * StringUtils.isMixedCase("abc")   = false
3671      * StringUtils.isMixedCase("aBc")   = true
3672      * StringUtils.isMixedCase("A c")   = true
3673      * StringUtils.isMixedCase("A1c")   = true
3674      * StringUtils.isMixedCase("a/C")   = true
3675      * StringUtils.isMixedCase("aC\t")  = true
3676      * </pre>
3677      *
3678      * @param cs the CharSequence to check, may be null
3679      * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
3680      * @since 3.5
3681      */
3682     public static boolean isMixedCase(final CharSequence cs) {
3683         if (isEmpty(cs) || cs.length() == 1) {
3684             return false;
3685         }
3686         boolean containsUppercase = false;
3687         boolean containsLowercase = false;
3688         final int sz = cs.length();
3689         for (int i = 0; i < sz; i++) {
3690             final char nowChar = cs.charAt(i);
3691             if (Character.isUpperCase(nowChar)) {
3692                 containsUppercase = true;
3693             } else if (Character.isLowerCase(nowChar)) {
3694                 containsLowercase = true;
3695             }
3696             if (containsUppercase && containsLowercase) {
3697                 return true;
3698             }
3699         }
3700         return false;
3701     }
3702 
3703     /**
3704      * Checks if none of the CharSequences are empty (""), null or whitespace only.
3705      *
3706      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3707      *
3708      * <pre>
3709      * StringUtils.isNoneBlank((String) null)    = false
3710      * StringUtils.isNoneBlank((String[]) null)  = true
3711      * StringUtils.isNoneBlank(null, "foo")      = false
3712      * StringUtils.isNoneBlank(null, null)       = false
3713      * StringUtils.isNoneBlank("", "bar")        = false
3714      * StringUtils.isNoneBlank("bob", "")        = false
3715      * StringUtils.isNoneBlank("  bob  ", null)  = false
3716      * StringUtils.isNoneBlank(" ", "bar")       = false
3717      * StringUtils.isNoneBlank(new String[] {})  = true
3718      * StringUtils.isNoneBlank(new String[]{""}) = false
3719      * StringUtils.isNoneBlank("foo", "bar")     = true
3720      * </pre>
3721      *
3722      * @param css  the CharSequences to check, may be null or empty
3723      * @return {@code true} if none of the CharSequences are empty or null or whitespace only
3724      * @since 3.2
3725      */
3726     public static boolean isNoneBlank(final CharSequence... css) {
3727       return !isAnyBlank(css);
3728     }
3729 
3730     /**
3731      * Checks if none of the CharSequences are empty ("") or null.
3732      *
3733      * <pre>
3734      * StringUtils.isNoneEmpty((String) null)    = false
3735      * StringUtils.isNoneEmpty((String[]) null)  = true
3736      * StringUtils.isNoneEmpty(null, "foo")      = false
3737      * StringUtils.isNoneEmpty("", "bar")        = false
3738      * StringUtils.isNoneEmpty("bob", "")        = false
3739      * StringUtils.isNoneEmpty("  bob  ", null)  = false
3740      * StringUtils.isNoneEmpty(new String[] {})  = true
3741      * StringUtils.isNoneEmpty(new String[]{""}) = false
3742      * StringUtils.isNoneEmpty(" ", "bar")       = true
3743      * StringUtils.isNoneEmpty("foo", "bar")     = true
3744      * </pre>
3745      *
3746      * @param css  the CharSequences to check, may be null or empty
3747      * @return {@code true} if none of the CharSequences are empty or null
3748      * @since 3.2
3749      */
3750     public static boolean isNoneEmpty(final CharSequence... css) {
3751       return !isAnyEmpty(css);
3752     }
3753 
3754     /**
3755      * Checks if a CharSequence is not empty (""), not null and not whitespace only.
3756      *
3757      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3758      *
3759      * <pre>
3760      * StringUtils.isNotBlank(null)      = false
3761      * StringUtils.isNotBlank("")        = false
3762      * StringUtils.isNotBlank(" ")       = false
3763      * StringUtils.isNotBlank("bob")     = true
3764      * StringUtils.isNotBlank("  bob  ") = true
3765      * </pre>
3766      *
3767      * @param cs  the CharSequence to check, may be null
3768      * @return {@code true} if the CharSequence is
3769      *  not empty and not null and not whitespace only
3770      * @since 2.0
3771      * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3772      */
3773     public static boolean isNotBlank(final CharSequence cs) {
3774         return !isBlank(cs);
3775     }
3776 
3777     /**
3778      * Checks if a CharSequence is not empty ("") and not null.
3779      *
3780      * <pre>
3781      * StringUtils.isNotEmpty(null)      = false
3782      * StringUtils.isNotEmpty("")        = false
3783      * StringUtils.isNotEmpty(" ")       = true
3784      * StringUtils.isNotEmpty("bob")     = true
3785      * StringUtils.isNotEmpty("  bob  ") = true
3786      * </pre>
3787      *
3788      * @param cs  the CharSequence to check, may be null
3789      * @return {@code true} if the CharSequence is not empty and not null
3790      * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3791      */
3792     public static boolean isNotEmpty(final CharSequence cs) {
3793         return !isEmpty(cs);
3794     }
3795 
3796     /**
3797      * Checks if the CharSequence contains only Unicode digits.
3798      * A decimal point is not a Unicode digit and returns false.
3799      *
3800      * <p>{@code null} will return {@code false}.
3801      * An empty CharSequence (length()=0) will return {@code false}.</p>
3802      *
3803      * <p>Note that the method does not allow for a leading sign, either positive or negative.
3804      * Also, if a String passes the numeric test, it may still generate a NumberFormatException
3805      * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
3806      * for int or long respectively.</p>
3807      *
3808      * <pre>
3809      * StringUtils.isNumeric(null)   = false
3810      * StringUtils.isNumeric("")     = false
3811      * StringUtils.isNumeric("  ")   = false
3812      * StringUtils.isNumeric("123")  = true
3813      * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3814      * StringUtils.isNumeric("12 3") = false
3815      * StringUtils.isNumeric("ab2c") = false
3816      * StringUtils.isNumeric("12-3") = false
3817      * StringUtils.isNumeric("12.3") = false
3818      * StringUtils.isNumeric("-123") = false
3819      * StringUtils.isNumeric("+123") = false
3820      * </pre>
3821      *
3822      * @param cs  the CharSequence to check, may be null
3823      * @return {@code true} if only contains digits, and is non-null
3824      * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3825      * @since 3.0 Changed "" to return false and not true
3826      */
3827     public static boolean isNumeric(final CharSequence cs) {
3828         if (isEmpty(cs)) {
3829             return false;
3830         }
3831         final int sz = cs.length();
3832         for (int i = 0; i < sz; i++) {
3833             if (!Character.isDigit(cs.charAt(i))) {
3834                 return false;
3835             }
3836         }
3837         return true;
3838     }
3839 
3840     /**
3841      * Checks if the CharSequence contains only Unicode digits or space
3842      * ({@code ' '}).
3843      * A decimal point is not a Unicode digit and returns false.
3844      *
3845      * <p>{@code null} will return {@code false}.
3846      * An empty CharSequence (length()=0) will return {@code true}.</p>
3847      *
3848      * <pre>
3849      * StringUtils.isNumericSpace(null)   = false
3850      * StringUtils.isNumericSpace("")     = true
3851      * StringUtils.isNumericSpace("  ")   = true
3852      * StringUtils.isNumericSpace("123")  = true
3853      * StringUtils.isNumericSpace("12 3") = true
3854      * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3855      * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3856      * StringUtils.isNumericSpace("ab2c") = false
3857      * StringUtils.isNumericSpace("12-3") = false
3858      * StringUtils.isNumericSpace("12.3") = false
3859      * </pre>
3860      *
3861      * @param cs  the CharSequence to check, may be null
3862      * @return {@code true} if only contains digits or space,
3863      *  and is non-null
3864      * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3865      */
3866     public static boolean isNumericSpace(final CharSequence cs) {
3867         if (cs == null) {
3868             return false;
3869         }
3870         final int sz = cs.length();
3871         for (int i = 0; i < sz; i++) {
3872             final char nowChar = cs.charAt(i);
3873             if (nowChar != ' ' && !Character.isDigit(nowChar)) {
3874                 return false;
3875             }
3876         }
3877         return true;
3878     }
3879 
3880     /**
3881      * Checks if the CharSequence contains only whitespace.
3882      *
3883      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3884      *
3885      * <p>{@code null} will return {@code false}.
3886      * An empty CharSequence (length()=0) will return {@code true}.</p>
3887      *
3888      * <pre>
3889      * StringUtils.isWhitespace(null)   = false
3890      * StringUtils.isWhitespace("")     = true
3891      * StringUtils.isWhitespace("  ")   = true
3892      * StringUtils.isWhitespace("abc")  = false
3893      * StringUtils.isWhitespace("ab2c") = false
3894      * StringUtils.isWhitespace("ab-c") = false
3895      * </pre>
3896      *
3897      * @param cs  the CharSequence to check, may be null
3898      * @return {@code true} if only contains whitespace, and is non-null
3899      * @since 2.0
3900      * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3901      */
3902     public static boolean isWhitespace(final CharSequence cs) {
3903         if (cs == null) {
3904             return false;
3905         }
3906         final int sz = cs.length();
3907         for (int i = 0; i < sz; i++) {
3908             if (!Character.isWhitespace(cs.charAt(i))) {
3909                 return false;
3910             }
3911         }
3912         return true;
3913     }
3914 
3915     /**
3916      * Joins the elements of the provided array into a single String containing the provided list of elements.
3917      *
3918      * <p>
3919      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3920      * by empty strings.
3921      * </p>
3922      *
3923      * <pre>
3924      * StringUtils.join(null, *)             = null
3925      * StringUtils.join([], *)               = ""
3926      * StringUtils.join([null], *)           = ""
3927      * StringUtils.join([false, false], ';') = "false;false"
3928      * </pre>
3929      *
3930      * @param array
3931      *            the array of values to join together, may be null
3932      * @param delimiter
3933      *            the separator character to use
3934      * @return the joined String, {@code null} if null array input
3935      * @since 3.12.0
3936      */
3937     public static String join(final boolean[] array, final char delimiter) {
3938         if (array == null) {
3939             return null;
3940         }
3941         return join(array, delimiter, 0, array.length);
3942     }
3943 
3944     /**
3945      * Joins the elements of the provided array into a single String containing the provided list of elements.
3946      *
3947      * <p>
3948      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3949      * by empty strings.
3950      * </p>
3951      *
3952      * <pre>
3953      * StringUtils.join(null, *)                  = null
3954      * StringUtils.join([], *)                    = ""
3955      * StringUtils.join([null], *)                = ""
3956      * StringUtils.join([true, false, true], ';') = "true;false;true"
3957      * </pre>
3958      *
3959      * @param array
3960      *            the array of values to join together, may be null
3961      * @param delimiter
3962      *            the separator character to use
3963      * @param startIndex
3964      *            the first index to start joining from. It is an error to pass in a start index past the end of the
3965      *            array
3966      * @param endIndex
3967      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3968      *            the array
3969      * @return the joined String, {@code null} if null array input
3970      * @since 3.12.0
3971      */
3972     public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3973         if (array == null) {
3974             return null;
3975         }
3976         if (endIndex - startIndex <= 0) {
3977             return EMPTY;
3978         }
3979         final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
3980         for (int i = startIndex; i < endIndex; i++) {
3981             stringBuilder
3982                     .append(array[i])
3983                     .append(delimiter);
3984         }
3985         return stringBuilder.substring(0, stringBuilder.length() - 1);
3986     }
3987 
3988     /**
3989      * Joins the elements of the provided array into a single String containing the provided list of elements.
3990      *
3991      * <p>
3992      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3993      * by empty strings.
3994      * </p>
3995      *
3996      * <pre>
3997      * StringUtils.join(null, *)         = null
3998      * StringUtils.join([], *)           = ""
3999      * StringUtils.join([null], *)       = ""
4000      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4001      * StringUtils.join([1, 2, 3], null) = "123"
4002      * </pre>
4003      *
4004      * @param array
4005      *            the array of values to join together, may be null
4006      * @param delimiter
4007      *            the separator character to use
4008      * @return the joined String, {@code null} if null array input
4009      * @since 3.2
4010      */
4011     public static String join(final byte[] array, final char delimiter) {
4012         if (array == null) {
4013             return null;
4014         }
4015         return join(array, delimiter, 0, array.length);
4016     }
4017 
4018     /**
4019      * Joins the elements of the provided array into a single String containing the provided list of elements.
4020      *
4021      * <p>
4022      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4023      * by empty strings.
4024      * </p>
4025      *
4026      * <pre>
4027      * StringUtils.join(null, *)         = null
4028      * StringUtils.join([], *)           = ""
4029      * StringUtils.join([null], *)       = ""
4030      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4031      * StringUtils.join([1, 2, 3], null) = "123"
4032      * </pre>
4033      *
4034      * @param array
4035      *            the array of values to join together, may be null
4036      * @param delimiter
4037      *            the separator character to use
4038      * @param startIndex
4039      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4040      *            array
4041      * @param endIndex
4042      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4043      *            the array
4044      * @return the joined String, {@code null} if null array input
4045      * @since 3.2
4046      */
4047     public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
4048         if (array == null) {
4049             return null;
4050         }
4051         if (endIndex - startIndex <= 0) {
4052             return EMPTY;
4053         }
4054         final StringBuilder stringBuilder = new StringBuilder();
4055         for (int i = startIndex; i < endIndex; i++) {
4056             stringBuilder
4057                     .append(array[i])
4058                     .append(delimiter);
4059         }
4060         return stringBuilder.substring(0, stringBuilder.length() - 1);
4061     }
4062 
4063     /**
4064      * Joins the elements of the provided array into a single String containing the provided list of elements.
4065      *
4066      * <p>
4067      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4068      * by empty strings.
4069      * </p>
4070      *
4071      * <pre>
4072      * StringUtils.join(null, *)         = null
4073      * StringUtils.join([], *)           = ""
4074      * StringUtils.join([null], *)       = ""
4075      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4076      * StringUtils.join([1, 2, 3], null) = "123"
4077      * </pre>
4078      *
4079      * @param array
4080      *            the array of values to join together, may be null
4081      * @param delimiter
4082      *            the separator character to use
4083      * @return the joined String, {@code null} if null array input
4084      * @since 3.2
4085      */
4086     public static String join(final char[] array, final char delimiter) {
4087         if (array == null) {
4088             return null;
4089         }
4090         return join(array, delimiter, 0, array.length);
4091     }
4092 
4093     /**
4094      * Joins the elements of the provided array into a single String containing the provided list of elements.
4095      *
4096      * <p>
4097      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4098      * by empty strings.
4099      * </p>
4100      *
4101      * <pre>
4102      * StringUtils.join(null, *)         = null
4103      * StringUtils.join([], *)           = ""
4104      * StringUtils.join([null], *)       = ""
4105      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4106      * StringUtils.join([1, 2, 3], null) = "123"
4107      * </pre>
4108      *
4109      * @param array
4110      *            the array of values to join together, may be null
4111      * @param delimiter
4112      *            the separator character to use
4113      * @param startIndex
4114      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4115      *            array
4116      * @param endIndex
4117      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4118      *            the array
4119      * @return the joined String, {@code null} if null array input
4120      * @since 3.2
4121      */
4122     public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
4123         if (array == null) {
4124             return null;
4125         }
4126         if (endIndex - startIndex <= 0) {
4127             return EMPTY;
4128         }
4129         final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
4130         for (int i = startIndex; i < endIndex; i++) {
4131             stringBuilder
4132                     .append(array[i])
4133                     .append(delimiter);
4134         }
4135         return stringBuilder.substring(0, stringBuilder.length() - 1);
4136     }
4137 
4138     /**
4139      * Joins the elements of the provided array into a single String containing the provided list of elements.
4140      *
4141      * <p>
4142      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4143      * by empty strings.
4144      * </p>
4145      *
4146      * <pre>
4147      * StringUtils.join(null, *)               = null
4148      * StringUtils.join([], *)                 = ""
4149      * StringUtils.join([null], *)             = ""
4150      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4151      * StringUtils.join([1, 2, 3], null) = "123"
4152      * </pre>
4153      *
4154      * @param array
4155      *            the array of values to join together, may be null
4156      * @param delimiter
4157      *            the separator character to use
4158      * @return the joined String, {@code null} if null array input
4159      * @since 3.2
4160      */
4161     public static String join(final double[] array, final char delimiter) {
4162         if (array == null) {
4163             return null;
4164         }
4165         return join(array, delimiter, 0, array.length);
4166     }
4167 
4168     /**
4169      * Joins the elements of the provided array into a single String containing the provided list of elements.
4170      *
4171      * <p>
4172      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4173      * by empty strings.
4174      * </p>
4175      *
4176      * <pre>
4177      * StringUtils.join(null, *)               = null
4178      * StringUtils.join([], *)                 = ""
4179      * StringUtils.join([null], *)             = ""
4180      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4181      * StringUtils.join([1, 2, 3], null) = "123"
4182      * </pre>
4183      *
4184      * @param array
4185      *            the array of values to join together, may be null
4186      * @param delimiter
4187      *            the separator character to use
4188      * @param startIndex
4189      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4190      *            array
4191      * @param endIndex
4192      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4193      *            the array
4194      * @return the joined String, {@code null} if null array input
4195      * @since 3.2
4196      */
4197     public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4198         if (array == null) {
4199             return null;
4200         }
4201         if (endIndex - startIndex <= 0) {
4202             return EMPTY;
4203         }
4204         final StringBuilder stringBuilder = new StringBuilder();
4205         for (int i = startIndex; i < endIndex; i++) {
4206             stringBuilder
4207                     .append(array[i])
4208                     .append(delimiter);
4209         }
4210         return stringBuilder.substring(0, stringBuilder.length() - 1);
4211     }
4212 
4213     /**
4214      * Joins the elements of the provided array into a single String containing the provided list of elements.
4215      *
4216      * <p>
4217      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4218      * by empty strings.
4219      * </p>
4220      *
4221      * <pre>
4222      * StringUtils.join(null, *)               = null
4223      * StringUtils.join([], *)                 = ""
4224      * StringUtils.join([null], *)             = ""
4225      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4226      * StringUtils.join([1, 2, 3], null) = "123"
4227      * </pre>
4228      *
4229      * @param array
4230      *            the array of values to join together, may be null
4231      * @param delimiter
4232      *            the separator character to use
4233      * @return the joined String, {@code null} if null array input
4234      * @since 3.2
4235      */
4236     public static String join(final float[] array, final char delimiter) {
4237         if (array == null) {
4238             return null;
4239         }
4240         return join(array, delimiter, 0, array.length);
4241     }
4242 
4243     /**
4244      * Joins the elements of the provided array into a single String containing the provided list of elements.
4245      *
4246      * <p>
4247      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4248      * by empty strings.
4249      * </p>
4250      *
4251      * <pre>
4252      * StringUtils.join(null, *)               = null
4253      * StringUtils.join([], *)                 = ""
4254      * StringUtils.join([null], *)             = ""
4255      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4256      * StringUtils.join([1, 2, 3], null) = "123"
4257      * </pre>
4258      *
4259      * @param array
4260      *            the array of values to join together, may be null
4261      * @param delimiter
4262      *            the separator character to use
4263      * @param startIndex
4264      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4265      *            array
4266      * @param endIndex
4267      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4268      *            the array
4269      * @return the joined String, {@code null} if null array input
4270      * @since 3.2
4271      */
4272     public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4273         if (array == null) {
4274             return null;
4275         }
4276         if (endIndex - startIndex <= 0) {
4277             return EMPTY;
4278         }
4279         final StringBuilder stringBuilder = new StringBuilder();
4280         for (int i = startIndex; i < endIndex; i++) {
4281             stringBuilder
4282                     .append(array[i])
4283                     .append(delimiter);
4284         }
4285         return stringBuilder.substring(0, stringBuilder.length() - 1);
4286     }
4287 
4288     /**
4289      * Joins the elements of the provided array into a single String containing the provided list of elements.
4290      *
4291      * <p>
4292      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4293      * by empty strings.
4294      * </p>
4295      *
4296      * <pre>
4297      * StringUtils.join(null, *)               = null
4298      * StringUtils.join([], *)                 = ""
4299      * StringUtils.join([null], *)             = ""
4300      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4301      * StringUtils.join([1, 2, 3], null) = "123"
4302      * </pre>
4303      *
4304      * @param array
4305      *            the array of values to join together, may be null
4306      * @param separator
4307      *            the separator character to use
4308      * @return the joined String, {@code null} if null array input
4309      * @since 3.2
4310      */
4311     public static String join(final int[] array, final char separator) {
4312         if (array == null) {
4313             return null;
4314         }
4315         return join(array, separator, 0, array.length);
4316     }
4317 
4318     /**
4319      * Joins the elements of the provided array into a single String containing the provided list of elements.
4320      *
4321      * <p>
4322      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4323      * by empty strings.
4324      * </p>
4325      *
4326      * <pre>
4327      * StringUtils.join(null, *)               = null
4328      * StringUtils.join([], *)                 = ""
4329      * StringUtils.join([null], *)             = ""
4330      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4331      * StringUtils.join([1, 2, 3], null) = "123"
4332      * </pre>
4333      *
4334      * @param array
4335      *            the array of values to join together, may be null
4336      * @param delimiter
4337      *            the separator character to use
4338      * @param startIndex
4339      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4340      *            array
4341      * @param endIndex
4342      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4343      *            the array
4344      * @return the joined String, {@code null} if null array input
4345      * @since 3.2
4346      */
4347     public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4348         if (array == null) {
4349             return null;
4350         }
4351         if (endIndex - startIndex <= 0) {
4352             return EMPTY;
4353         }
4354         final StringBuilder stringBuilder = new StringBuilder();
4355         for (int i = startIndex; i < endIndex; i++) {
4356             stringBuilder
4357                     .append(array[i])
4358                     .append(delimiter);
4359         }
4360         return stringBuilder.substring(0, stringBuilder.length() - 1);
4361     }
4362 
4363     /**
4364      * Joins the elements of the provided {@link Iterable} into
4365      * a single String containing the provided elements.
4366      *
4367      * <p>No delimiter is added before or after the list. Null objects or empty
4368      * strings within the iteration are represented by empty strings.</p>
4369      *
4370      * <p>See the examples here: {@link #join(Object[],char)}.</p>
4371      *
4372      * @param iterable  the {@link Iterable} providing the values to join together, may be null
4373      * @param separator  the separator character to use
4374      * @return the joined String, {@code null} if null iterator input
4375      * @since 2.3
4376      */
4377     public static String join(final Iterable<?> iterable, final char separator) {
4378         return iterable != null ? join(iterable.iterator(), separator) : null;
4379     }
4380 
4381     /**
4382      * Joins the elements of the provided {@link Iterable} into
4383      * a single String containing the provided elements.
4384      *
4385      * <p>No delimiter is added before or after the list.
4386      * A {@code null} separator is the same as an empty String ("").</p>
4387      *
4388      * <p>See the examples here: {@link #join(Object[],String)}.</p>
4389      *
4390      * @param iterable  the {@link Iterable} providing the values to join together, may be null
4391      * @param separator  the separator character to use, null treated as ""
4392      * @return the joined String, {@code null} if null iterator input
4393      * @since 2.3
4394      */
4395     public static String join(final Iterable<?> iterable, final String separator) {
4396         return iterable != null ? join(iterable.iterator(), separator) : null;
4397     }
4398 
4399     /**
4400      * Joins the elements of the provided {@link Iterator} into
4401      * a single String containing the provided elements.
4402      *
4403      * <p>No delimiter is added before or after the list. Null objects or empty
4404      * strings within the iteration are represented by empty strings.</p>
4405      *
4406      * <p>See the examples here: {@link #join(Object[],char)}.</p>
4407      *
4408      * @param iterator  the {@link Iterator} of values to join together, may be null
4409      * @param separator  the separator character to use
4410      * @return the joined String, {@code null} if null iterator input
4411      * @since 2.0
4412      */
4413     public static String join(final Iterator<?> iterator, final char separator) {
4414         // handle null, zero and one elements before building a buffer
4415         if (iterator == null) {
4416             return null;
4417         }
4418         if (!iterator.hasNext()) {
4419             return EMPTY;
4420         }
4421         return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(String.valueOf(separator)), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
4422     }
4423 
4424     /**
4425      * Joins the elements of the provided {@link Iterator} into
4426      * a single String containing the provided elements.
4427      *
4428      * <p>No delimiter is added before or after the list.
4429      * A {@code null} separator is the same as an empty String ("").</p>
4430      *
4431      * <p>See the examples here: {@link #join(Object[],String)}.</p>
4432      *
4433      * @param iterator  the {@link Iterator} of values to join together, may be null
4434      * @param separator  the separator character to use, null treated as ""
4435      * @return the joined String, {@code null} if null iterator input
4436      */
4437     public static String join(final Iterator<?> iterator, final String separator) {
4438         // handle null, zero and one elements before building a buffer
4439         if (iterator == null) {
4440             return null;
4441         }
4442         if (!iterator.hasNext()) {
4443             return EMPTY;
4444         }
4445         return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(separator), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
4446     }
4447 
4448     /**
4449      * Joins the elements of the provided {@link List} into a single String
4450      * containing the provided list of elements.
4451      *
4452      * <p>No delimiter is added before or after the list.
4453      * Null objects or empty strings within the array are represented by
4454      * empty strings.</p>
4455      *
4456      * <pre>
4457      * StringUtils.join(null, *)               = null
4458      * StringUtils.join([], *)                 = ""
4459      * StringUtils.join([null], *)             = ""
4460      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4461      * StringUtils.join(["a", "b", "c"], null) = "abc"
4462      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4463      * </pre>
4464      *
4465      * @param list  the {@link List} of values to join together, may be null
4466      * @param separator  the separator character to use
4467      * @param startIndex the first index to start joining from.  It is
4468      * an error to pass in a start index past the end of the list
4469      * @param endIndex the index to stop joining from (exclusive). It is
4470      * an error to pass in an end index past the end of the list
4471      * @return the joined String, {@code null} if null list input
4472      * @since 3.8
4473      */
4474     public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4475         if (list == null) {
4476             return null;
4477         }
4478         final int noOfItems = endIndex - startIndex;
4479         if (noOfItems <= 0) {
4480             return EMPTY;
4481         }
4482         final List<?> subList = list.subList(startIndex, endIndex);
4483         return join(subList.iterator(), separator);
4484     }
4485 
4486     /**
4487      * Joins the elements of the provided {@link List} into a single String
4488      * containing the provided list of elements.
4489      *
4490      * <p>No delimiter is added before or after the list.
4491      * Null objects or empty strings within the array are represented by
4492      * empty strings.</p>
4493      *
4494      * <pre>
4495      * StringUtils.join(null, *)               = null
4496      * StringUtils.join([], *)                 = ""
4497      * StringUtils.join([null], *)             = ""
4498      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4499      * StringUtils.join(["a", "b", "c"], null) = "abc"
4500      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4501      * </pre>
4502      *
4503      * @param list  the {@link List} of values to join together, may be null
4504      * @param separator  the separator character to use
4505      * @param startIndex the first index to start joining from.  It is
4506      * an error to pass in a start index past the end of the list
4507      * @param endIndex the index to stop joining from (exclusive). It is
4508      * an error to pass in an end index past the end of the list
4509      * @return the joined String, {@code null} if null list input
4510      * @since 3.8
4511      */
4512     public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4513         if (list == null) {
4514             return null;
4515         }
4516         final int noOfItems = endIndex - startIndex;
4517         if (noOfItems <= 0) {
4518             return EMPTY;
4519         }
4520         final List<?> subList = list.subList(startIndex, endIndex);
4521         return join(subList.iterator(), separator);
4522     }
4523 
4524     /**
4525      * Joins the elements of the provided array into a single String containing the provided list of elements.
4526      *
4527      * <p>
4528      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4529      * by empty strings.
4530      * </p>
4531      *
4532      * <pre>
4533      * StringUtils.join(null, *)               = null
4534      * StringUtils.join([], *)                 = ""
4535      * StringUtils.join([null], *)             = ""
4536      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4537      * StringUtils.join([1, 2, 3], null) = "123"
4538      * </pre>
4539      *
4540      * @param array
4541      *            the array of values to join together, may be null
4542      * @param separator
4543      *            the separator character to use
4544      * @return the joined String, {@code null} if null array input
4545      * @since 3.2
4546      */
4547     public static String join(final long[] array, final char separator) {
4548         if (array == null) {
4549             return null;
4550         }
4551         return join(array, separator, 0, array.length);
4552     }
4553 
4554     /**
4555      * Joins the elements of the provided array into a single String containing the provided list of elements.
4556      *
4557      * <p>
4558      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4559      * by empty strings.
4560      * </p>
4561      *
4562      * <pre>
4563      * StringUtils.join(null, *)               = null
4564      * StringUtils.join([], *)                 = ""
4565      * StringUtils.join([null], *)             = ""
4566      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4567      * StringUtils.join([1, 2, 3], null) = "123"
4568      * </pre>
4569      *
4570      * @param array
4571      *            the array of values to join together, may be null
4572      * @param delimiter
4573      *            the separator character to use
4574      * @param startIndex
4575      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4576      *            array
4577      * @param endIndex
4578      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4579      *            the array
4580      * @return the joined String, {@code null} if null array input
4581      * @since 3.2
4582      */
4583     public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4584         if (array == null) {
4585             return null;
4586         }
4587         if (endIndex - startIndex <= 0) {
4588             return EMPTY;
4589         }
4590         final StringBuilder stringBuilder = new StringBuilder();
4591         for (int i = startIndex; i < endIndex; i++) {
4592             stringBuilder
4593                     .append(array[i])
4594                     .append(delimiter);
4595         }
4596         return stringBuilder.substring(0, stringBuilder.length() - 1);
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      * Null objects or empty strings within the array are represented by
4605      * empty strings.</p>
4606      *
4607      * <pre>
4608      * StringUtils.join(null, *)               = null
4609      * StringUtils.join([], *)                 = ""
4610      * StringUtils.join([null], *)             = ""
4611      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4612      * StringUtils.join(["a", "b", "c"], null) = "abc"
4613      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4614      * </pre>
4615      *
4616      * @param array  the array of values to join together, may be null
4617      * @param delimiter  the separator character to use
4618      * @return the joined String, {@code null} if null array input
4619      * @since 2.0
4620      */
4621     public static String join(final Object[] array, final char delimiter) {
4622         if (array == null) {
4623             return null;
4624         }
4625         return join(array, delimiter, 0, array.length);
4626     }
4627 
4628     /**
4629      * Joins the elements of the provided array into a single String
4630      * containing the provided list of elements.
4631      *
4632      * <p>No delimiter is added before or after the list.
4633      * Null objects or empty strings within the array are represented by
4634      * empty strings.</p>
4635      *
4636      * <pre>
4637      * StringUtils.join(null, *)               = null
4638      * StringUtils.join([], *)                 = ""
4639      * StringUtils.join([null], *)             = ""
4640      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4641      * StringUtils.join(["a", "b", "c"], null) = "abc"
4642      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4643      * </pre>
4644      *
4645      * @param array  the array of values to join together, may be null
4646      * @param delimiter  the separator character to use
4647      * @param startIndex the first index to start joining from.  It is
4648      * an error to pass in a start index past the end of the array
4649      * @param endIndex the index to stop joining from (exclusive). It is
4650      * an error to pass in an end index past the end of the array
4651      * @return the joined String, {@code null} if null array input
4652      * @since 2.0
4653      */
4654     public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4655         return join(array, String.valueOf(delimiter), startIndex, endIndex);
4656     }
4657 
4658     /**
4659      * Joins the elements of the provided array into a single String
4660      * containing the provided list of elements.
4661      *
4662      * <p>No delimiter is added before or after the list.
4663      * A {@code null} separator is the same as an empty String ("").
4664      * Null objects or empty strings within the array are represented by
4665      * empty strings.</p>
4666      *
4667      * <pre>
4668      * StringUtils.join(null, *)                = null
4669      * StringUtils.join([], *)                  = ""
4670      * StringUtils.join([null], *)              = ""
4671      * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4672      * StringUtils.join(["a", "b", "c"], null)  = "abc"
4673      * StringUtils.join(["a", "b", "c"], "")    = "abc"
4674      * StringUtils.join([null, "", "a"], ',')   = ",,a"
4675      * </pre>
4676      *
4677      * @param array  the array of values to join together, may be null
4678      * @param delimiter  the separator character to use, null treated as ""
4679      * @return the joined String, {@code null} if null array input
4680      */
4681     public static String join(final Object[] array, final String delimiter) {
4682         return array != null ? join(array, toStringOrEmpty(delimiter), 0, array.length) : null;
4683     }
4684 
4685     /**
4686      * Joins the elements of the provided array into a single String
4687      * containing the provided list of elements.
4688      *
4689      * <p>No delimiter is added before or after the list.
4690      * A {@code null} separator is the same as an empty String ("").
4691      * Null objects or empty strings within the array are represented by
4692      * empty strings.</p>
4693      *
4694      * <pre>
4695      * StringUtils.join(null, *, *, *)                = null
4696      * StringUtils.join([], *, *, *)                  = ""
4697      * StringUtils.join([null], *, *, *)              = ""
4698      * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4699      * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4700      * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4701      * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4702      * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4703      * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4704      * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4705      * </pre>
4706      *
4707      * @param array  the array of values to join together, may be null
4708      * @param delimiter  the separator character to use, null treated as ""
4709      * @param startIndex the first index to start joining from.
4710      * @param endIndex the index to stop joining from (exclusive).
4711      * @return the joined String, {@code null} if null array input; or the empty string
4712      * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4713      * {@code endIndex - startIndex}
4714      * @throws ArrayIndexOutOfBoundsException ife<br>
4715      * {@code startIndex < 0} or <br>
4716      * {@code startIndex >= array.length()} or <br>
4717      * {@code endIndex < 0} or <br>
4718      * {@code endIndex > array.length()}
4719      */
4720     public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4721         return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4722             .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, StringUtils::toStringOrEmpty)) : null;
4723     }
4724 
4725     /**
4726      * Joins the elements of the provided array into a single String containing the provided list of elements.
4727      *
4728      * <p>
4729      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4730      * by empty strings.
4731      * </p>
4732      *
4733      * <pre>
4734      * StringUtils.join(null, *)               = null
4735      * StringUtils.join([], *)                 = ""
4736      * StringUtils.join([null], *)             = ""
4737      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4738      * StringUtils.join([1, 2, 3], null) = "123"
4739      * </pre>
4740      *
4741      * @param array
4742      *            the array of values to join together, may be null
4743      * @param delimiter
4744      *            the separator character to use
4745      * @return the joined String, {@code null} if null array input
4746      * @since 3.2
4747      */
4748     public static String join(final short[] array, final char delimiter) {
4749         if (array == null) {
4750             return null;
4751         }
4752         return join(array, delimiter, 0, array.length);
4753     }
4754 
4755     /**
4756      * Joins the elements of the provided array into a single String containing the provided list of elements.
4757      *
4758      * <p>
4759      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4760      * by empty strings.
4761      * </p>
4762      *
4763      * <pre>
4764      * StringUtils.join(null, *)               = null
4765      * StringUtils.join([], *)                 = ""
4766      * StringUtils.join([null], *)             = ""
4767      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4768      * StringUtils.join([1, 2, 3], null) = "123"
4769      * </pre>
4770      *
4771      * @param array
4772      *            the array of values to join together, may be null
4773      * @param delimiter
4774      *            the separator character to use
4775      * @param startIndex
4776      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4777      *            array
4778      * @param endIndex
4779      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4780      *            the array
4781      * @return the joined String, {@code null} if null array input
4782      * @since 3.2
4783      */
4784     public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4785         if (array == null) {
4786             return null;
4787         }
4788         if (endIndex - startIndex <= 0) {
4789             return EMPTY;
4790         }
4791         final StringBuilder stringBuilder = new StringBuilder();
4792         for (int i = startIndex; i < endIndex; i++) {
4793             stringBuilder
4794                     .append(array[i])
4795                     .append(delimiter);
4796         }
4797         return stringBuilder.substring(0, stringBuilder.length() - 1);
4798     }
4799 
4800     /**
4801      * Joins the elements of the provided array into a single String
4802      * containing the provided list of elements.
4803      *
4804      * <p>No separator is added to the joined String.
4805      * Null objects or empty strings within the array are represented by
4806      * empty strings.</p>
4807      *
4808      * <pre>
4809      * StringUtils.join(null)            = null
4810      * StringUtils.join([])              = ""
4811      * StringUtils.join([null])          = ""
4812      * StringUtils.join(["a", "b", "c"]) = "abc"
4813      * StringUtils.join([null, "", "a"]) = "a"
4814      * </pre>
4815      *
4816      * @param <T> the specific type of values to join together
4817      * @param elements  the values to join together, may be null
4818      * @return the joined String, {@code null} if null array input
4819      * @since 2.0
4820      * @since 3.0 Changed signature to use varargs
4821      */
4822     @SafeVarargs
4823     public static <T> String join(final T... elements) {
4824         return join(elements, null);
4825     }
4826 
4827     /**
4828      * Joins the elements of the provided varargs into a
4829      * single String containing the provided elements.
4830      *
4831      * <p>No delimiter is added before or after the list.
4832      * {@code null} elements and separator are treated as empty Strings ("").</p>
4833      *
4834      * <pre>
4835      * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4836      * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4837      * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4838      * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4839      * </pre>
4840      *
4841      * @param delimiter the separator character to use, null treated as ""
4842      * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
4843      * @return the joined String.
4844      * @throws IllegalArgumentException if a null varargs is provided
4845      * @since 3.5
4846      */
4847     public static String joinWith(final String delimiter, final Object... array) {
4848         if (array == null) {
4849             throw new IllegalArgumentException("Object varargs must not be null");
4850         }
4851         return join(array, delimiter);
4852     }
4853 
4854     /**
4855      * Finds the last index within a CharSequence, handling {@code null}.
4856      * This method uses {@link String#lastIndexOf(String)} if possible.
4857      *
4858      * <p>A {@code null} CharSequence will return {@code -1}.</p>
4859      *
4860      * <pre>
4861      * StringUtils.lastIndexOf(null, *)          = -1
4862      * StringUtils.lastIndexOf(*, null)          = -1
4863      * StringUtils.lastIndexOf("", "")           = 0
4864      * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4865      * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4866      * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4867      * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4868      * </pre>
4869      *
4870      * @param seq  the CharSequence to check, may be null
4871      * @param searchSeq  the CharSequence to find, may be null
4872      * @return the last index of the search String,
4873      *  -1 if no match or {@code null} string input
4874      * @since 2.0
4875      * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4876      */
4877     public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4878         if (seq == null) {
4879             return INDEX_NOT_FOUND;
4880         }
4881         return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
4882     }
4883 
4884     /**
4885      * Finds the last index within a CharSequence, handling {@code null}.
4886      * This method uses {@link String#lastIndexOf(String, int)} if possible.
4887      *
4888      * <p>A {@code null} CharSequence will return {@code -1}.
4889      * A negative start position returns {@code -1}.
4890      * An empty ("") search CharSequence always matches unless the start position is negative.
4891      * A start position greater than the string length searches the whole string.
4892      * The search starts at the startPos and works backwards; matches starting after the start
4893      * position are ignored.
4894      * </p>
4895      *
4896      * <pre>
4897      * StringUtils.lastIndexOf(null, *, *)          = -1
4898      * StringUtils.lastIndexOf(*, null, *)          = -1
4899      * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4900      * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4901      * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4902      * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4903      * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4904      * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4905      * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4906      * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4907      * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4908      * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4909      * </pre>
4910      *
4911      * @param seq  the CharSequence to check, may be null
4912      * @param searchSeq  the CharSequence to find, may be null
4913      * @param startPos  the start position, negative treated as zero
4914      * @return the last index of the search CharSequence (always &le; startPos),
4915      *  -1 if no match or {@code null} string input
4916      * @since 2.0
4917      * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4918      */
4919     public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4920         return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
4921     }
4922 
4923     /**
4924      * Returns the index within {@code seq} of the last occurrence of
4925      * the specified character. For values of {@code searchChar} in the
4926      * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
4927      * units) returned is the largest value <em>k</em> such that:
4928      * <blockquote><pre>
4929      * this.charAt(<em>k</em>) == searchChar
4930      * </pre></blockquote>
4931      * is true. For other values of {@code searchChar}, it is the
4932      * largest value <em>k</em> such that:
4933      * <blockquote><pre>
4934      * this.codePointAt(<em>k</em>) == searchChar
4935      * </pre></blockquote>
4936      * is true.  In either case, if no such character occurs in this
4937      * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4938      * {@link CharSequence} will return {@code -1}. The
4939      * {@code seq} {@link CharSequence} object is searched backwards
4940      * starting at the last character.
4941      *
4942      * <pre>
4943      * StringUtils.lastIndexOf(null, *)         = -1
4944      * StringUtils.lastIndexOf("", *)           = -1
4945      * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4946      * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4947      * </pre>
4948      *
4949      * @param seq  the {@link CharSequence} to check, may be null
4950      * @param searchChar  the character to find
4951      * @return the last index of the search character,
4952      *  -1 if no match or {@code null} string input
4953      * @since 2.0
4954      * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4955      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4956      */
4957     public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4958         if (isEmpty(seq)) {
4959             return INDEX_NOT_FOUND;
4960         }
4961         return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4962     }
4963 
4964     /**
4965      * Returns the index within {@code seq} of the last occurrence of
4966      * the specified character, searching backward starting at the
4967      * specified index. For values of {@code searchChar} in the range
4968      * from 0 to 0xFFFF (inclusive), the index returned is the largest
4969      * value <em>k</em> such that:
4970      * <blockquote><pre>
4971      * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4972      * </pre></blockquote>
4973      * is true. For other values of {@code searchChar}, it is the
4974      * largest value <em>k</em> such that:
4975      * <blockquote><pre>
4976      * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4977      * </pre></blockquote>
4978      * is true. In either case, if no such character occurs in {@code seq}
4979      * at or before position {@code startPos}, then
4980      * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4981      * {@link CharSequence} will return {@code -1}. A start position greater
4982      * than the string length searches the whole string.
4983      * The search starts at the {@code startPos} and works backwards;
4984      * matches starting after the start position are ignored.
4985      *
4986      * <p>All indices are specified in {@code char} values
4987      * (Unicode code units).
4988      *
4989      * <pre>
4990      * StringUtils.lastIndexOf(null, *, *)          = -1
4991      * StringUtils.lastIndexOf("", *,  *)           = -1
4992      * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4993      * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4994      * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4995      * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4996      * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4997      * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4998      * </pre>
4999      *
5000      * @param seq  the CharSequence to check, may be null
5001      * @param searchChar  the character to find
5002      * @param startPos  the start position
5003      * @return the last index of the search character (always &le; startPos),
5004      *  -1 if no match or {@code null} string input
5005      * @since 2.0
5006      * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
5007      */
5008     public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
5009         if (isEmpty(seq)) {
5010             return INDEX_NOT_FOUND;
5011         }
5012         return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
5013     }
5014 
5015     /**
5016      * Find the latest index of any substring in a set of potential substrings.
5017      *
5018      * <p>A {@code null} CharSequence will return {@code -1}.
5019      * A {@code null} search array will return {@code -1}.
5020      * A {@code null} or zero length search array entry will be ignored,
5021      * but a search array containing "" will return the length of {@code str}
5022      * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
5023      *
5024      * <pre>
5025      * StringUtils.lastIndexOfAny(null, *)                    = -1
5026      * StringUtils.lastIndexOfAny(*, null)                    = -1
5027      * StringUtils.lastIndexOfAny(*, [])                      = -1
5028      * StringUtils.lastIndexOfAny(*, [null])                  = -1
5029      * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
5030      * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
5031      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5032      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
5033      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
5034      * </pre>
5035      *
5036      * @param str  the CharSequence to check, may be null
5037      * @param searchStrs  the CharSequences to search for, may be null
5038      * @return the last index of any of the CharSequences, -1 if no match
5039      * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
5040      */
5041     public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
5042         if (str == null || searchStrs == null) {
5043             return INDEX_NOT_FOUND;
5044         }
5045         int ret = INDEX_NOT_FOUND;
5046         int tmp;
5047         for (final CharSequence search : searchStrs) {
5048             if (search == null) {
5049                 continue;
5050             }
5051             tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
5052             if (tmp > ret) {
5053                 ret = tmp;
5054             }
5055         }
5056         return ret;
5057     }
5058 
5059     /**
5060      * Case in-sensitive find of the last index within a CharSequence.
5061      *
5062      * <p>A {@code null} CharSequence will return {@code -1}.
5063      * A negative start position returns {@code -1}.
5064      * An empty ("") search CharSequence always matches unless the start position is negative.
5065      * A start position greater than the string length searches the whole string.</p>
5066      *
5067      * <pre>
5068      * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
5069      * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
5070      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
5071      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
5072      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
5073      * </pre>
5074      *
5075      * @param str  the CharSequence to check, may be null
5076      * @param searchStr  the CharSequence to find, may be null
5077      * @return the first index of the search CharSequence,
5078      *  -1 if no match or {@code null} string input
5079      * @since 2.5
5080      * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
5081      */
5082     public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
5083         if (str == null || searchStr == null) {
5084             return INDEX_NOT_FOUND;
5085         }
5086         return lastIndexOfIgnoreCase(str, searchStr, str.length());
5087     }
5088 
5089     /**
5090      * Case in-sensitive find of the last index within a CharSequence
5091      * from the specified position.
5092      *
5093      * <p>A {@code null} CharSequence will return {@code -1}.
5094      * A negative start position returns {@code -1}.
5095      * An empty ("") search CharSequence always matches unless the start position is negative.
5096      * A start position greater than the string length searches the whole string.
5097      * The search starts at the startPos and works backwards; matches starting after the start
5098      * position are ignored.
5099      * </p>
5100      *
5101      * <pre>
5102      * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
5103      * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
5104      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
5105      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
5106      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
5107      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
5108      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
5109      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
5110      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
5111      * </pre>
5112      *
5113      * @param str  the CharSequence to check, may be null
5114      * @param searchStr  the CharSequence to find, may be null
5115      * @param startPos  the start position
5116      * @return the last index of the search CharSequence (always &le; startPos),
5117      *  -1 if no match or {@code null} input
5118      * @since 2.5
5119      * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
5120      */
5121     public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
5122         if (str == null || searchStr == null) {
5123             return INDEX_NOT_FOUND;
5124         }
5125         final int searchStrLength = searchStr.length();
5126         final int strLength = str.length();
5127         if (startPos > strLength - searchStrLength) {
5128             startPos = strLength - searchStrLength;
5129         }
5130         if (startPos < 0) {
5131             return INDEX_NOT_FOUND;
5132         }
5133         if (searchStrLength == 0) {
5134             return startPos;
5135         }
5136 
5137         for (int i = startPos; i >= 0; i--) {
5138             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) {
5139                 return i;
5140             }
5141         }
5142         return INDEX_NOT_FOUND;
5143     }
5144 
5145     /**
5146      * Finds the n-th last index within a String, handling {@code null}.
5147      * This method uses {@link String#lastIndexOf(String)}.
5148      *
5149      * <p>A {@code null} String will return {@code -1}.</p>
5150      *
5151      * <pre>
5152      * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5153      * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5154      * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5155      * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5156      * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5157      * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5158      * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5159      * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5160      * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5161      * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5162      * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5163      * </pre>
5164      *
5165      * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
5166      *
5167      * <pre>
5168      *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5169      * </pre>
5170      *
5171      * @param str  the CharSequence to check, may be null
5172      * @param searchStr  the CharSequence to find, may be null
5173      * @param ordinal  the n-th last {@code searchStr} to find
5174      * @return the n-th last index of the search CharSequence,
5175      *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5176      * @since 2.5
5177      * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5178      */
5179     public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5180         return ordinalIndexOf(str, searchStr, ordinal, true);
5181     }
5182 
5183     /**
5184      * Gets the leftmost {@code len} characters of a String.
5185      *
5186      * <p>If {@code len} characters are not available, or the
5187      * String is {@code null}, the String will be returned without
5188      * an exception. An empty String is returned if len is negative.</p>
5189      *
5190      * <pre>
5191      * StringUtils.left(null, *)    = null
5192      * StringUtils.left(*, -ve)     = ""
5193      * StringUtils.left("", *)      = ""
5194      * StringUtils.left("abc", 0)   = ""
5195      * StringUtils.left("abc", 2)   = "ab"
5196      * StringUtils.left("abc", 4)   = "abc"
5197      * </pre>
5198      *
5199      * @param str  the String to get the leftmost characters from, may be null
5200      * @param len  the length of the required String
5201      * @return the leftmost characters, {@code null} if null String input
5202      */
5203     public static String left(final String str, final int len) {
5204         if (str == null) {
5205             return null;
5206         }
5207         if (len < 0) {
5208             return EMPTY;
5209         }
5210         if (str.length() <= len) {
5211             return str;
5212         }
5213         return str.substring(0, len);
5214     }
5215 
5216     /**
5217      * Left pad a String with spaces (' ').
5218      *
5219      * <p>The String is padded to the size of {@code size}.</p>
5220      *
5221      * <pre>
5222      * StringUtils.leftPad(null, *)   = null
5223      * StringUtils.leftPad("", 3)     = "   "
5224      * StringUtils.leftPad("bat", 3)  = "bat"
5225      * StringUtils.leftPad("bat", 5)  = "  bat"
5226      * StringUtils.leftPad("bat", 1)  = "bat"
5227      * StringUtils.leftPad("bat", -1) = "bat"
5228      * </pre>
5229      *
5230      * @param str  the String to pad out, may be null
5231      * @param size  the size to pad to
5232      * @return left padded String or original String if no padding is necessary,
5233      *  {@code null} if null String input
5234      */
5235     public static String leftPad(final String str, final int size) {
5236         return leftPad(str, size, ' ');
5237     }
5238 
5239     /**
5240      * Left pad a String with a specified character.
5241      *
5242      * <p>Pad to a size of {@code size}.</p>
5243      *
5244      * <pre>
5245      * StringUtils.leftPad(null, *, *)     = null
5246      * StringUtils.leftPad("", 3, 'z')     = "zzz"
5247      * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5248      * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5249      * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5250      * StringUtils.leftPad("bat", -1, 'z') = "bat"
5251      * </pre>
5252      *
5253      * @param str  the String to pad out, may be null
5254      * @param size  the size to pad to
5255      * @param padChar  the character to pad with
5256      * @return left padded String or original String if no padding is necessary,
5257      *  {@code null} if null String input
5258      * @since 2.0
5259      */
5260     public static String leftPad(final String str, final int size, final char padChar) {
5261         if (str == null) {
5262             return null;
5263         }
5264         final int pads = size - str.length();
5265         if (pads <= 0) {
5266             return str; // returns original String when possible
5267         }
5268         if (pads > PAD_LIMIT) {
5269             return leftPad(str, size, String.valueOf(padChar));
5270         }
5271         return repeat(padChar, pads).concat(str);
5272     }
5273 
5274     /**
5275      * Left pad a String with a specified String.
5276      *
5277      * <p>Pad to a size of {@code size}.</p>
5278      *
5279      * <pre>
5280      * StringUtils.leftPad(null, *, *)      = null
5281      * StringUtils.leftPad("", 3, "z")      = "zzz"
5282      * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5283      * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5284      * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5285      * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5286      * StringUtils.leftPad("bat", -1, "yz") = "bat"
5287      * StringUtils.leftPad("bat", 5, null)  = "  bat"
5288      * StringUtils.leftPad("bat", 5, "")    = "  bat"
5289      * </pre>
5290      *
5291      * @param str  the String to pad out, may be null
5292      * @param size  the size to pad to
5293      * @param padStr  the String to pad with, null or empty treated as single space
5294      * @return left padded String or original String if no padding is necessary,
5295      *  {@code null} if null String input
5296      */
5297     public static String leftPad(final String str, final int size, String padStr) {
5298         if (str == null) {
5299             return null;
5300         }
5301         if (isEmpty(padStr)) {
5302             padStr = SPACE;
5303         }
5304         final int padLen = padStr.length();
5305         final int strLen = str.length();
5306         final int pads = size - strLen;
5307         if (pads <= 0) {
5308             return str; // returns original String when possible
5309         }
5310         if (padLen == 1 && pads <= PAD_LIMIT) {
5311             return leftPad(str, size, padStr.charAt(0));
5312         }
5313 
5314         if (pads == padLen) {
5315             return padStr.concat(str);
5316         }
5317         if (pads < padLen) {
5318             return padStr.substring(0, pads).concat(str);
5319         }
5320         final char[] padding = new char[pads];
5321         final char[] padChars = padStr.toCharArray();
5322         for (int i = 0; i < pads; i++) {
5323             padding[i] = padChars[i % padLen];
5324         }
5325         return new String(padding).concat(str);
5326     }
5327 
5328     /**
5329      * Gets a CharSequence length or {@code 0} if the CharSequence is
5330      * {@code null}.
5331      *
5332      * @param cs
5333      *            a CharSequence or {@code null}
5334      * @return CharSequence length or {@code 0} if the CharSequence is
5335      *         {@code null}.
5336      * @since 2.4
5337      * @since 3.0 Changed signature from length(String) to length(CharSequence)
5338      */
5339     public static int length(final CharSequence cs) {
5340         return cs == null ? 0 : cs.length();
5341     }
5342 
5343     /**
5344      * Converts a String to lower case as per {@link String#toLowerCase()}.
5345      *
5346      * <p>A {@code null} input String returns {@code null}.</p>
5347      *
5348      * <pre>
5349      * StringUtils.lowerCase(null)  = null
5350      * StringUtils.lowerCase("")    = ""
5351      * StringUtils.lowerCase("aBc") = "abc"
5352      * </pre>
5353      *
5354      * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
5355      * the result of this method is affected by the current locale.
5356      * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
5357      * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
5358      *
5359      * @param str  the String to lower case, may be null
5360      * @return the lower cased String, {@code null} if null String input
5361      */
5362     public static String lowerCase(final String str) {
5363         if (str == null) {
5364             return null;
5365         }
5366         return str.toLowerCase();
5367     }
5368 
5369     /**
5370      * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5371      *
5372      * <p>A {@code null} input String returns {@code null}.</p>
5373      *
5374      * <pre>
5375      * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5376      * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5377      * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5378      * </pre>
5379      *
5380      * @param str  the String to lower case, may be null
5381      * @param locale  the locale that defines the case transformation rules, must not be null
5382      * @return the lower cased String, {@code null} if null String input
5383      * @since 2.5
5384      */
5385     public static String lowerCase(final String str, final Locale locale) {
5386         if (str == null) {
5387             return null;
5388         }
5389         return str.toLowerCase(LocaleUtils.toLocale(locale));
5390     }
5391 
5392     private static int[] matches(final CharSequence first, final CharSequence second) {
5393         final CharSequence max;
5394         final CharSequence min;
5395         if (first.length() > second.length()) {
5396             max = first;
5397             min = second;
5398         } else {
5399             max = second;
5400             min = first;
5401         }
5402         final int range = Math.max(max.length() / 2 - 1, 0);
5403         final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5404         final boolean[] matchFlags = new boolean[max.length()];
5405         int matches = 0;
5406         for (int mi = 0; mi < min.length(); mi++) {
5407             final char c1 = min.charAt(mi);
5408             for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5409                 if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5410                     matchIndexes[mi] = xi;
5411                     matchFlags[xi] = true;
5412                     matches++;
5413                     break;
5414                 }
5415             }
5416         }
5417         final char[] ms1 = new char[matches];
5418         final char[] ms2 = new char[matches];
5419         for (int i = 0, si = 0; i < min.length(); i++) {
5420             if (matchIndexes[i] != -1) {
5421                 ms1[si] = min.charAt(i);
5422                 si++;
5423             }
5424         }
5425         for (int i = 0, si = 0; i < max.length(); i++) {
5426             if (matchFlags[i]) {
5427                 ms2[si] = max.charAt(i);
5428                 si++;
5429             }
5430         }
5431         int transpositions = 0;
5432         for (int mi = 0; mi < ms1.length; mi++) {
5433             if (ms1[mi] != ms2[mi]) {
5434                 transpositions++;
5435             }
5436         }
5437         int prefix = 0;
5438         for (int mi = 0; mi < min.length(); mi++) {
5439             if (first.charAt(mi) != second.charAt(mi)) {
5440                 break;
5441             }
5442             prefix++;
5443         }
5444         return new int[] { matches, transpositions / 2, prefix, max.length() };
5445     }
5446 
5447     /**
5448      * Gets {@code len} characters from the middle of a String.
5449      *
5450      * <p>If {@code len} characters are not available, the remainder
5451      * of the String will be returned without an exception. If the
5452      * String is {@code null}, {@code null} will be returned.
5453      * An empty String is returned if len is negative or exceeds the
5454      * length of {@code str}.</p>
5455      *
5456      * <pre>
5457      * StringUtils.mid(null, *, *)    = null
5458      * StringUtils.mid(*, *, -ve)     = ""
5459      * StringUtils.mid("", 0, *)      = ""
5460      * StringUtils.mid("abc", 0, 2)   = "ab"
5461      * StringUtils.mid("abc", 0, 4)   = "abc"
5462      * StringUtils.mid("abc", 2, 4)   = "c"
5463      * StringUtils.mid("abc", 4, 2)   = ""
5464      * StringUtils.mid("abc", -2, 2)  = "ab"
5465      * </pre>
5466      *
5467      * @param str  the String to get the characters from, may be null
5468      * @param pos  the position to start from, negative treated as zero
5469      * @param len  the length of the required String
5470      * @return the middle characters, {@code null} if null String input
5471      */
5472     public static String mid(final String str, int pos, final int len) {
5473         if (str == null) {
5474             return null;
5475         }
5476         if (len < 0 || pos > str.length()) {
5477             return EMPTY;
5478         }
5479         if (pos < 0) {
5480             pos = 0;
5481         }
5482         if (str.length() <= pos + len) {
5483             return str.substring(pos);
5484         }
5485         return str.substring(pos, pos + len);
5486     }
5487 
5488     /**
5489      * Similar to <a
5490      * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
5491      * -space</a>
5492      *
5493      * <p>
5494      * The function returns the argument string with whitespace normalized by using
5495      * {@code {@link #trim(String)}} to remove leading and trailing whitespace
5496      * and then replacing sequences of whitespace characters by a single space.
5497      * </p>
5498      * In XML Whitespace characters are the same as those allowed by the <a
5499      * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
5500      * <p>
5501      * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5502      *
5503      * <p>For reference:</p>
5504      * <ul>
5505      * <li>\x0B = vertical tab</li>
5506      * <li>\f = #xC = form feed</li>
5507      * <li>#x20 = space</li>
5508      * <li>#x9 = \t</li>
5509      * <li>#xA = \n</li>
5510      * <li>#xD = \r</li>
5511      * </ul>
5512      *
5513      * <p>
5514      * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
5515      * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
5516      * ends of this String.
5517      * </p>
5518      *
5519      * @see Pattern
5520      * @see #trim(String)
5521      * @see <a
5522      *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5523      * @param str the source String to normalize whitespaces from, may be null
5524      * @return the modified string with whitespace normalized, {@code null} if null String input
5525      *
5526      * @since 3.0
5527      */
5528     public static String normalizeSpace(final String str) {
5529         // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5530         // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5531         if (isEmpty(str)) {
5532             return str;
5533         }
5534         final int size = str.length();
5535         final char[] newChars = new char[size];
5536         int count = 0;
5537         int whitespacesCount = 0;
5538         boolean startWhitespaces = true;
5539         for (int i = 0; i < size; i++) {
5540             final char actualChar = str.charAt(i);
5541             final boolean isWhitespace = Character.isWhitespace(actualChar);
5542             if (isWhitespace) {
5543                 if (whitespacesCount == 0 && !startWhitespaces) {
5544                     newChars[count++] = SPACE.charAt(0);
5545                 }
5546                 whitespacesCount++;
5547             } else {
5548                 startWhitespaces = false;
5549                 newChars[count++] = actualChar == 160 ? 32 : actualChar;
5550                 whitespacesCount = 0;
5551             }
5552         }
5553         if (startWhitespaces) {
5554             return EMPTY;
5555         }
5556         return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5557     }
5558 
5559     /**
5560      * Finds the n-th index within a CharSequence, handling {@code null}.
5561      * This method uses {@link String#indexOf(String)} if possible.
5562      * <p><b>Note:</b> The code starts looking for a match at the start of the target,
5563      * incrementing the starting index by one after each successful match
5564      * (unless {@code searchStr} is an empty string in which case the position
5565      * is never incremented and {@code 0} is returned immediately).
5566      * This means that matches may overlap.</p>
5567      * <p>A {@code null} CharSequence will return {@code -1}.</p>
5568      *
5569      * <pre>
5570      * StringUtils.ordinalIndexOf(null, *, *)          = -1
5571      * StringUtils.ordinalIndexOf(*, null, *)          = -1
5572      * StringUtils.ordinalIndexOf("", "", *)           = 0
5573      * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5574      * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5575      * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5576      * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5577      * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5578      * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5579      * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5580      * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5581      * </pre>
5582      *
5583      * <p>Matches may overlap:</p>
5584      * <pre>
5585      * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5586      * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5587      * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5588      *
5589      * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5590      * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5591      * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5592      * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5593      * </pre>
5594      *
5595      * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
5596      *
5597      * <pre>
5598      *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5599      * </pre>
5600      *
5601      * @param str  the CharSequence to check, may be null
5602      * @param searchStr  the CharSequence to find, may be null
5603      * @param ordinal  the n-th {@code searchStr} to find
5604      * @return the n-th index of the search CharSequence,
5605      *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5606      * @since 2.1
5607      * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5608      */
5609     public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5610         return ordinalIndexOf(str, searchStr, ordinal, false);
5611     }
5612 
5613     /**
5614      * Finds the n-th index within a String, handling {@code null}.
5615      * This method uses {@link String#indexOf(String)} if possible.
5616      * <p>Note that matches may overlap<p>
5617      *
5618      * <p>A {@code null} CharSequence will return {@code -1}.</p>
5619      *
5620      * @param str  the CharSequence to check, may be null
5621      * @param searchStr  the CharSequence to find, may be null
5622      * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
5623      * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
5624      * @return the n-th index of the search CharSequence,
5625      *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5626      */
5627     // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5628     private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5629         if (str == null || searchStr == null || ordinal <= 0) {
5630             return INDEX_NOT_FOUND;
5631         }
5632         if (searchStr.length() == 0) {
5633             return lastIndex ? str.length() : 0;
5634         }
5635         int found = 0;
5636         // set the initial index beyond the end of the string
5637         // this is to allow for the initial index decrement/increment
5638         int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5639         do {
5640             if (lastIndex) {
5641                 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5642             } else {
5643                 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5644             }
5645             if (index < 0) {
5646                 return index;
5647             }
5648             found++;
5649         } while (found < ordinal);
5650         return index;
5651     }
5652 
5653     /**
5654      * Overlays part of a String with another String.
5655      *
5656      * <p>A {@code null} string input returns {@code null}.
5657      * A negative index is treated as zero.
5658      * An index greater than the string length is treated as the string length.
5659      * The start index is always the smaller of the two indices.</p>
5660      *
5661      * <pre>
5662      * StringUtils.overlay(null, *, *, *)            = null
5663      * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5664      * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5665      * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5666      * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5667      * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5668      * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5669      * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5670      * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5671      * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5672      * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5673      * </pre>
5674      *
5675      * @param str  the String to do overlaying in, may be null
5676      * @param overlay  the String to overlay, may be null
5677      * @param start  the position to start overlaying at
5678      * @param end  the position to stop overlaying before
5679      * @return overlayed String, {@code null} if null String input
5680      * @since 2.0
5681      */
5682     public static String overlay(final String str, String overlay, int start, int end) {
5683         if (str == null) {
5684             return null;
5685         }
5686         if (overlay == null) {
5687             overlay = EMPTY;
5688         }
5689         final int len = str.length();
5690         if (start < 0) {
5691             start = 0;
5692         }
5693         if (start > len) {
5694             start = len;
5695         }
5696         if (end < 0) {
5697             end = 0;
5698         }
5699         if (end > len) {
5700             end = len;
5701         }
5702         if (start > end) {
5703             final int temp = start;
5704             start = end;
5705             end = temp;
5706         }
5707         return str.substring(0, start) +
5708             overlay +
5709             str.substring(end);
5710     }
5711 
5712     /**
5713      * Prepends the prefix to the start of the string if the string does not
5714      * already start with any of the prefixes.
5715      *
5716      * @param str The string.
5717      * @param prefix The prefix to prepend to the start of the string.
5718      * @param ignoreCase Indicates whether the compare should ignore case.
5719      * @param prefixes Additional prefixes that are valid (optional).
5720      *
5721      * @return A new String if prefix was prepended, the same string otherwise.
5722      */
5723     private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
5724         if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
5725             return str;
5726         }
5727         if (ArrayUtils.isNotEmpty(prefixes)) {
5728             for (final CharSequence p : prefixes) {
5729                 if (startsWith(str, p, ignoreCase)) {
5730                     return str;
5731                 }
5732             }
5733         }
5734         return prefix + str;
5735     }
5736 
5737     /**
5738      * Prepends the prefix to the start of the string if the string does not
5739      * already start with any of the prefixes.
5740      *
5741      * <pre>
5742      * StringUtils.prependIfMissing(null, null) = null
5743      * StringUtils.prependIfMissing("abc", null) = "abc"
5744      * StringUtils.prependIfMissing("", "xyz") = "xyz"
5745      * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5746      * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5747      * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5748      * </pre>
5749      * <p>With additional prefixes,</p>
5750      * <pre>
5751      * StringUtils.prependIfMissing(null, null, null) = null
5752      * StringUtils.prependIfMissing("abc", null, null) = "abc"
5753      * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5754      * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5755      * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5756      * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5757      * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5758      * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5759      * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5760      * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5761      * </pre>
5762      *
5763      * @param str The string.
5764      * @param prefix The prefix to prepend to the start of the string.
5765      * @param prefixes Additional prefixes that are valid.
5766      *
5767      * @return A new String if prefix was prepended, the same string otherwise.
5768      *
5769      * @since 3.2
5770      */
5771     public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5772         return prependIfMissing(str, prefix, false, prefixes);
5773     }
5774 
5775     /**
5776      * Prepends the prefix to the start of the string if the string does not
5777      * already start, case-insensitive, with any of the prefixes.
5778      *
5779      * <pre>
5780      * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5781      * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5782      * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5783      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5784      * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5785      * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5786      * </pre>
5787      * <p>With additional prefixes,</p>
5788      * <pre>
5789      * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5790      * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5791      * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5792      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5793      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5794      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5795      * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5796      * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5797      * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5798      * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5799      * </pre>
5800      *
5801      * @param str The string.
5802      * @param prefix The prefix to prepend to the start of the string.
5803      * @param prefixes Additional prefixes that are valid (optional).
5804      *
5805      * @return A new String if prefix was prepended, the same string otherwise.
5806      *
5807      * @since 3.2
5808      */
5809     public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5810         return prependIfMissing(str, prefix, true, prefixes);
5811     }
5812 
5813     /**
5814      * Removes all occurrences of a character from within the source string.
5815      *
5816      * <p>A {@code null} source string will return {@code null}.
5817      * An empty ("") source string will return the empty string.</p>
5818      *
5819      * <pre>
5820      * StringUtils.remove(null, *)       = null
5821      * StringUtils.remove("", *)         = ""
5822      * StringUtils.remove("queued", 'u') = "qeed"
5823      * StringUtils.remove("queued", 'z') = "queued"
5824      * </pre>
5825      *
5826      * @param str  the source String to search, may be null
5827      * @param remove  the char to search for and remove, may be null
5828      * @return the substring with the char removed if found,
5829      *  {@code null} if null String input
5830      * @since 2.1
5831      */
5832     public static String remove(final String str, final char remove) {
5833         if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5834             return str;
5835         }
5836         final char[] chars = str.toCharArray();
5837         int pos = 0;
5838         for (int i = 0; i < chars.length; i++) {
5839             if (chars[i] != remove) {
5840                 chars[pos++] = chars[i];
5841             }
5842         }
5843         return new String(chars, 0, pos);
5844     }
5845 
5846     /**
5847      * Removes all occurrences of a substring from within the source string.
5848      *
5849      * <p>A {@code null} source string will return {@code null}.
5850      * An empty ("") source string will return the empty string.
5851      * A {@code null} remove string will return the source string.
5852      * An empty ("") remove string will return the source string.</p>
5853      *
5854      * <pre>
5855      * StringUtils.remove(null, *)        = null
5856      * StringUtils.remove("", *)          = ""
5857      * StringUtils.remove(*, null)        = *
5858      * StringUtils.remove(*, "")          = *
5859      * StringUtils.remove("queued", "ue") = "qd"
5860      * StringUtils.remove("queued", "zz") = "queued"
5861      * </pre>
5862      *
5863      * @param str  the source String to search, may be null
5864      * @param remove  the String to search for and remove, may be null
5865      * @return the substring with the string removed if found,
5866      *  {@code null} if null String input
5867      * @since 2.1
5868      */
5869     public static String remove(final String str, final String remove) {
5870         if (isEmpty(str) || isEmpty(remove)) {
5871             return str;
5872         }
5873         return replace(str, remove, EMPTY, -1);
5874     }
5875 
5876     /**
5877      * Removes each substring of the text String that matches the given regular expression.
5878      *
5879      * This method is a {@code null} safe equivalent to:
5880      * <ul>
5881      *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5882      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5883      * </ul>
5884      *
5885      * <p>A {@code null} reference passed to this method is a no-op.</p>
5886      *
5887      * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5888      * is NOT automatically added.
5889      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5890      * DOTALL is also known as single-line mode in Perl.</p>
5891      *
5892      * <pre>{@code
5893      * StringUtils.removeAll(null, *)      = null
5894      * StringUtils.removeAll("any", (String) null)  = "any"
5895      * StringUtils.removeAll("any", "")    = "any"
5896      * StringUtils.removeAll("any", ".*")  = ""
5897      * StringUtils.removeAll("any", ".+")  = ""
5898      * StringUtils.removeAll("abc", ".?")  = ""
5899      * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5900      * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5901      * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5902      * }</pre>
5903      *
5904      * @param text  text to remove from, may be null
5905      * @param regex  the regular expression to which this string is to be matched
5906      * @return  the text with any removes processed,
5907      *              {@code null} if null String input
5908      *
5909      * @throws  java.util.regex.PatternSyntaxException
5910      *              if the regular expression's syntax is invalid
5911      *
5912      * @see #replaceAll(String, String, String)
5913      * @see #removePattern(String, String)
5914      * @see String#replaceAll(String, String)
5915      * @see java.util.regex.Pattern
5916      * @see java.util.regex.Pattern#DOTALL
5917      * @since 3.5
5918      *
5919      * @deprecated Moved to RegExUtils.
5920      */
5921     @Deprecated
5922     public static String removeAll(final String text, final String regex) {
5923         return RegExUtils.removeAll(text, regex);
5924     }
5925 
5926     /**
5927      * Removes a substring only if it is at the end of a source string,
5928      * otherwise returns the source string.
5929      *
5930      * <p>A {@code null} source string will return {@code null}.
5931      * An empty ("") source string will return the empty string.
5932      * A {@code null} search string will return the source string.</p>
5933      *
5934      * <pre>
5935      * StringUtils.removeEnd(null, *)      = null
5936      * StringUtils.removeEnd("", *)        = ""
5937      * StringUtils.removeEnd(*, null)      = *
5938      * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5939      * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5940      * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5941      * StringUtils.removeEnd("abc", "")    = "abc"
5942      * </pre>
5943      *
5944      * @param str  the source String to search, may be null
5945      * @param remove  the String to search for and remove, may be null
5946      * @return the substring with the string removed if found,
5947      *  {@code null} if null String input
5948      * @since 2.1
5949      */
5950     public static String removeEnd(final String str, final String remove) {
5951         if (isEmpty(str) || isEmpty(remove)) {
5952             return str;
5953         }
5954         if (str.endsWith(remove)) {
5955             return str.substring(0, str.length() - remove.length());
5956         }
5957         return str;
5958     }
5959 
5960     /**
5961      * Case-insensitive removal of a substring if it is at the end of a source string,
5962      * otherwise returns the source string.
5963      *
5964      * <p>A {@code null} source string will return {@code null}.
5965      * An empty ("") source string will return the empty string.
5966      * A {@code null} search string will return the source string.</p>
5967      *
5968      * <pre>
5969      * StringUtils.removeEndIgnoreCase(null, *)      = null
5970      * StringUtils.removeEndIgnoreCase("", *)        = ""
5971      * StringUtils.removeEndIgnoreCase(*, null)      = *
5972      * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5973      * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5974      * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5975      * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5976      * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5977      * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5978      * </pre>
5979      *
5980      * @param str  the source String to search, may be null
5981      * @param remove  the String to search for (case-insensitive) and remove, may be null
5982      * @return the substring with the string removed if found,
5983      *  {@code null} if null String input
5984      * @since 2.4
5985      */
5986     public static String removeEndIgnoreCase(final String str, final String remove) {
5987         if (isEmpty(str) || isEmpty(remove)) {
5988             return str;
5989         }
5990         if (endsWithIgnoreCase(str, remove)) {
5991             return str.substring(0, str.length() - remove.length());
5992         }
5993         return str;
5994     }
5995 
5996     /**
5997      * Removes the first substring of the text string that matches the given regular expression.
5998      *
5999      * This method is a {@code null} safe equivalent to:
6000      * <ul>
6001      *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
6002      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
6003      * </ul>
6004      *
6005      * <p>A {@code null} reference passed to this method is a no-op.</p>
6006      *
6007      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6008      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6009      * DOTALL is also known as single-line mode in Perl.</p>
6010      *
6011      * <pre>{@code
6012      * StringUtils.removeFirst(null, *)      = null
6013      * StringUtils.removeFirst("any", (String) null)  = "any"
6014      * StringUtils.removeFirst("any", "")    = "any"
6015      * StringUtils.removeFirst("any", ".*")  = ""
6016      * StringUtils.removeFirst("any", ".+")  = ""
6017      * StringUtils.removeFirst("abc", ".?")  = "bc"
6018      * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
6019      * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
6020      * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
6021      * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
6022      * }</pre>
6023      *
6024      * @param text  text to remove from, may be null
6025      * @param regex  the regular expression to which this string is to be matched
6026      * @return  the text with the first replacement processed,
6027      *              {@code null} if null String input
6028      *
6029      * @throws  java.util.regex.PatternSyntaxException
6030      *              if the regular expression's syntax is invalid
6031      *
6032      * @see #replaceFirst(String, String, String)
6033      * @see String#replaceFirst(String, String)
6034      * @see java.util.regex.Pattern
6035      * @see java.util.regex.Pattern#DOTALL
6036      * @since 3.5
6037      *
6038      * @deprecated Moved to RegExUtils.
6039      */
6040     @Deprecated
6041     public static String removeFirst(final String text, final String regex) {
6042         return replaceFirst(text, regex, EMPTY);
6043     }
6044 
6045     /**
6046      * Case-insensitive removal of all occurrences of a substring from within
6047      * the source string.
6048      *
6049      * <p>
6050      * A {@code null} source string will return {@code null}. An empty ("")
6051      * source string will return the empty string. A {@code null} remove string
6052      * will return the source string. An empty ("") remove string will return
6053      * the source string.
6054      * </p>
6055      *
6056      * <pre>
6057      * StringUtils.removeIgnoreCase(null, *)        = null
6058      * StringUtils.removeIgnoreCase("", *)          = ""
6059      * StringUtils.removeIgnoreCase(*, null)        = *
6060      * StringUtils.removeIgnoreCase(*, "")          = *
6061      * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
6062      * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
6063      * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
6064      * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
6065      * </pre>
6066      *
6067      * @param str
6068      *            the source String to search, may be null
6069      * @param remove
6070      *            the String to search for (case-insensitive) and remove, may be
6071      *            null
6072      * @return the substring with the string removed if found, {@code null} if
6073      *         null String input
6074      * @since 3.5
6075      */
6076     public static String removeIgnoreCase(final String str, final String remove) {
6077         return replaceIgnoreCase(str, remove, EMPTY, -1);
6078     }
6079 
6080     /**
6081      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
6082      *
6083      * This call is a {@code null} safe equivalent to:
6084      * <ul>
6085      * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
6086      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
6087      * </ul>
6088      *
6089      * <p>A {@code null} reference passed to this method is a no-op.</p>
6090      *
6091      * <pre>{@code
6092      * StringUtils.removePattern(null, *)       = null
6093      * StringUtils.removePattern("any", (String) null)   = "any"
6094      * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
6095      * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
6096      * }</pre>
6097      *
6098      * @param source
6099      *            the source string
6100      * @param regex
6101      *            the regular expression to which this string is to be matched
6102      * @return The resulting {@link String}
6103      * @see #replacePattern(String, String, String)
6104      * @see String#replaceAll(String, String)
6105      * @see Pattern#DOTALL
6106      * @since 3.2
6107      * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6108      *
6109      * @deprecated Moved to RegExUtils.
6110      */
6111     @Deprecated
6112     public static String removePattern(final String source, final String regex) {
6113         return RegExUtils.removePattern(source, regex);
6114     }
6115 
6116     /**
6117      * Removes a char only if it is at the beginning of a source string,
6118      * otherwise returns the source string.
6119      *
6120      * <p>A {@code null} source string will return {@code null}.
6121      * An empty ("") source string will return the empty string.
6122      * A {@code null} search char will return the source string.</p>
6123      *
6124      * <pre>
6125      * StringUtils.removeStart(null, *)      = null
6126      * StringUtils.removeStart("", *)        = ""
6127      * StringUtils.removeStart(*, null)      = *
6128      * StringUtils.removeStart("/path", '/') = "path"
6129      * StringUtils.removeStart("path", '/')  = "path"
6130      * StringUtils.removeStart("path", 0)    = "path"
6131      * </pre>
6132      *
6133      * @param str  the source String to search, may be null.
6134      * @param remove  the char to search for and remove.
6135      * @return the substring with the char removed if found,
6136      *  {@code null} if null String input.
6137      * @since 3.13.0
6138      */
6139     public static String removeStart(final String str, final char remove) {
6140         if (isEmpty(str)) {
6141             return str;
6142         }
6143         return str.charAt(0) == remove ? str.substring(1) : str;
6144     }
6145 
6146     /**
6147      * Removes a substring only if it is at the beginning of a source string,
6148      * otherwise returns the source string.
6149      *
6150      * <p>A {@code null} source string will return {@code null}.
6151      * An empty ("") source string will return the empty string.
6152      * A {@code null} search string will return the source string.</p>
6153      *
6154      * <pre>
6155      * StringUtils.removeStart(null, *)      = null
6156      * StringUtils.removeStart("", *)        = ""
6157      * StringUtils.removeStart(*, null)      = *
6158      * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
6159      * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
6160      * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
6161      * StringUtils.removeStart("abc", "")    = "abc"
6162      * </pre>
6163      *
6164      * @param str  the source String to search, may be null
6165      * @param remove  the String to search for and remove, may be null
6166      * @return the substring with the string removed if found,
6167      *  {@code null} if null String input
6168      * @since 2.1
6169      */
6170     public static String removeStart(final String str, final String remove) {
6171         if (isEmpty(str) || isEmpty(remove)) {
6172             return str;
6173         }
6174         if (str.startsWith(remove)) {
6175             return str.substring(remove.length());
6176         }
6177         return str;
6178     }
6179 
6180     /**
6181      * Case-insensitive removal of a substring if it is at the beginning of a source string,
6182      * otherwise returns the source string.
6183      *
6184      * <p>A {@code null} source string will return {@code null}.
6185      * An empty ("") source string will return the empty string.
6186      * A {@code null} search string will return the source string.</p>
6187      *
6188      * <pre>
6189      * StringUtils.removeStartIgnoreCase(null, *)      = null
6190      * StringUtils.removeStartIgnoreCase("", *)        = ""
6191      * StringUtils.removeStartIgnoreCase(*, null)      = *
6192      * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6193      * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6194      * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6195      * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6196      * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
6197      * </pre>
6198      *
6199      * @param str  the source String to search, may be null
6200      * @param remove  the String to search for (case-insensitive) and remove, may be null
6201      * @return the substring with the string removed if found,
6202      *  {@code null} if null String input
6203      * @since 2.4
6204      */
6205     public static String removeStartIgnoreCase(final String str, final String remove) {
6206         if (str != null && startsWithIgnoreCase(str, remove)) {
6207             return str.substring(length(remove));
6208         }
6209         return str;
6210     }
6211 
6212     /**
6213      * Returns padding using the specified delimiter repeated
6214      * to a given length.
6215      *
6216      * <pre>
6217      * StringUtils.repeat('e', 0)  = ""
6218      * StringUtils.repeat('e', 3)  = "eee"
6219      * StringUtils.repeat('e', -2) = ""
6220      * </pre>
6221      *
6222      * <p>Note: this method does not support padding with
6223      * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6224      * as they require a pair of {@code char}s to be represented.
6225      * If you are needing to support full I18N of your applications
6226      * consider using {@link #repeat(String, int)} instead.
6227      * </p>
6228      *
6229      * @param ch  character to repeat
6230      * @param repeat  number of times to repeat char, negative treated as zero
6231      * @return String with repeated character
6232      * @see #repeat(String, int)
6233      */
6234     public static String repeat(final char ch, final int repeat) {
6235         if (repeat <= 0) {
6236             return EMPTY;
6237         }
6238         return new String(ArrayFill.fill(new char[repeat], ch));
6239     }
6240 
6241     /**
6242      * Repeat a String {@code repeat} times to form a
6243      * new String.
6244      *
6245      * <pre>
6246      * StringUtils.repeat(null, 2) = null
6247      * StringUtils.repeat("", 0)   = ""
6248      * StringUtils.repeat("", 2)   = ""
6249      * StringUtils.repeat("a", 3)  = "aaa"
6250      * StringUtils.repeat("ab", 2) = "abab"
6251      * StringUtils.repeat("a", -2) = ""
6252      * </pre>
6253      *
6254      * @param str  the String to repeat, may be null
6255      * @param repeat  number of times to repeat str, negative treated as zero
6256      * @return a new String consisting of the original String repeated,
6257      *  {@code null} if null String input
6258      */
6259     public static String repeat(final String str, final int repeat) {
6260         // Performance tuned for 2.0 (JDK1.4)
6261         if (str == null) {
6262             return null;
6263         }
6264         if (repeat <= 0) {
6265             return EMPTY;
6266         }
6267         final int inputLength = str.length();
6268         if (repeat == 1 || inputLength == 0) {
6269             return str;
6270         }
6271         if (inputLength == 1 && repeat <= PAD_LIMIT) {
6272             return repeat(str.charAt(0), repeat);
6273         }
6274 
6275         final int outputLength = inputLength * repeat;
6276         switch (inputLength) {
6277             case 1 :
6278                 return repeat(str.charAt(0), repeat);
6279             case 2 :
6280                 final char ch0 = str.charAt(0);
6281                 final char ch1 = str.charAt(1);
6282                 final char[] output2 = new char[outputLength];
6283                 for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6284                     output2[i] = ch0;
6285                     output2[i + 1] = ch1;
6286                 }
6287                 return new String(output2);
6288             default :
6289                 final StringBuilder buf = new StringBuilder(outputLength);
6290                 for (int i = 0; i < repeat; i++) {
6291                     buf.append(str);
6292                 }
6293                 return buf.toString();
6294         }
6295     }
6296 
6297     /**
6298      * Repeat a String {@code repeat} times to form a
6299      * new String, with a String separator injected each time.
6300      *
6301      * <pre>
6302      * StringUtils.repeat(null, null, 2) = null
6303      * StringUtils.repeat(null, "x", 2)  = null
6304      * StringUtils.repeat("", null, 0)   = ""
6305      * StringUtils.repeat("", "", 2)     = ""
6306      * StringUtils.repeat("", "x", 3)    = "xx"
6307      * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6308      * </pre>
6309      *
6310      * @param str        the String to repeat, may be null
6311      * @param separator  the String to inject, may be null
6312      * @param repeat     number of times to repeat str, negative treated as zero
6313      * @return a new String consisting of the original String repeated,
6314      *  {@code null} if null String input
6315      * @since 2.5
6316      */
6317     public static String repeat(final String str, final String separator, final int repeat) {
6318         if (str == null || separator == null) {
6319             return repeat(str, repeat);
6320         }
6321         // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6322         final String result = repeat(str + separator, repeat);
6323         return removeEnd(result, separator);
6324     }
6325 
6326     /**
6327      * Replaces all occurrences of a String within another String.
6328      *
6329      * <p>A {@code null} reference passed to this method is a no-op.</p>
6330      *
6331      * <pre>
6332      * StringUtils.replace(null, *, *)        = null
6333      * StringUtils.replace("", *, *)          = ""
6334      * StringUtils.replace("any", null, *)    = "any"
6335      * StringUtils.replace("any", *, null)    = "any"
6336      * StringUtils.replace("any", "", *)      = "any"
6337      * StringUtils.replace("aba", "a", null)  = "aba"
6338      * StringUtils.replace("aba", "a", "")    = "b"
6339      * StringUtils.replace("aba", "a", "z")   = "zbz"
6340      * </pre>
6341      *
6342      * @see #replace(String text, String searchString, String replacement, int max)
6343      * @param text  text to search and replace in, may be null
6344      * @param searchString  the String to search for, may be null
6345      * @param replacement  the String to replace it with, may be null
6346      * @return the text with any replacements processed,
6347      *  {@code null} if null String input
6348      */
6349     public static String replace(final String text, final String searchString, final String replacement) {
6350         return replace(text, searchString, replacement, -1);
6351     }
6352 
6353     /**
6354      * Replaces a String with another String inside a larger String,
6355      * for the first {@code max} values of the search String.
6356      *
6357      * <p>A {@code null} reference passed to this method is a no-op.</p>
6358      *
6359      * <pre>
6360      * StringUtils.replace(null, *, *, *)         = null
6361      * StringUtils.replace("", *, *, *)           = ""
6362      * StringUtils.replace("any", null, *, *)     = "any"
6363      * StringUtils.replace("any", *, null, *)     = "any"
6364      * StringUtils.replace("any", "", *, *)       = "any"
6365      * StringUtils.replace("any", *, *, 0)        = "any"
6366      * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6367      * StringUtils.replace("abaa", "a", "", -1)   = "b"
6368      * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6369      * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6370      * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6371      * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6372      * </pre>
6373      *
6374      * @param text  text to search and replace in, may be null
6375      * @param searchString  the String to search for, may be null
6376      * @param replacement  the String to replace it with, may be null
6377      * @param max  maximum number of values to replace, or {@code -1} if no maximum
6378      * @return the text with any replacements processed,
6379      *  {@code null} if null String input
6380      */
6381     public static String replace(final String text, final String searchString, final String replacement, final int max) {
6382         return replace(text, searchString, replacement, max, false);
6383     }
6384 
6385     /**
6386      * Replaces a String with another String inside a larger String,
6387      * for the first {@code max} values of the search String,
6388      * case-sensitively/insensitively based on {@code ignoreCase} value.
6389      *
6390      * <p>A {@code null} reference passed to this method is a no-op.</p>
6391      *
6392      * <pre>
6393      * StringUtils.replace(null, *, *, *, false)         = null
6394      * StringUtils.replace("", *, *, *, false)           = ""
6395      * StringUtils.replace("any", null, *, *, false)     = "any"
6396      * StringUtils.replace("any", *, null, *, false)     = "any"
6397      * StringUtils.replace("any", "", *, *, false)       = "any"
6398      * StringUtils.replace("any", *, *, 0, false)        = "any"
6399      * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
6400      * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
6401      * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
6402      * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
6403      * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
6404      * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
6405      * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
6406      * </pre>
6407      *
6408      * @param text  text to search and replace in, may be null
6409      * @param searchString  the String to search for (case-insensitive), may be null
6410      * @param replacement  the String to replace it with, may be null
6411      * @param max  maximum number of values to replace, or {@code -1} if no maximum
6412      * @param ignoreCase if true replace is case-insensitive, otherwise case-sensitive
6413      * @return the text with any replacements processed,
6414      *  {@code null} if null String input
6415      */
6416      private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
6417          if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
6418              return text;
6419          }
6420          if (ignoreCase) {
6421              searchString = searchString.toLowerCase();
6422          }
6423          int start = 0;
6424          int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6425          if (end == INDEX_NOT_FOUND) {
6426              return text;
6427          }
6428          final int replLength = searchString.length();
6429          int increase = Math.max(replacement.length() - replLength, 0);
6430          increase *= max < 0 ? 16 : Math.min(max, 64);
6431          final StringBuilder buf = new StringBuilder(text.length() + increase);
6432          while (end != INDEX_NOT_FOUND) {
6433              buf.append(text, start, end).append(replacement);
6434              start = end + replLength;
6435              if (--max == 0) {
6436                  break;
6437              }
6438              end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6439          }
6440          buf.append(text, start, text.length());
6441          return buf.toString();
6442      }
6443 
6444     /**
6445      * Replaces each substring of the text String that matches the given regular expression
6446      * with the given replacement.
6447      *
6448      * This method is a {@code null} safe equivalent to:
6449      * <ul>
6450      *  <li>{@code text.replaceAll(regex, replacement)}</li>
6451      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6452      * </ul>
6453      *
6454      * <p>A {@code null} reference passed to this method is a no-op.</p>
6455      *
6456      * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
6457      * is NOT automatically added.
6458      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6459      * DOTALL is also known as single-line mode in Perl.</p>
6460      *
6461      * <pre>{@code
6462      * StringUtils.replaceAll(null, *, *)       = null
6463      * StringUtils.replaceAll("any", (String) null, *)   = "any"
6464      * StringUtils.replaceAll("any", *, null)   = "any"
6465      * StringUtils.replaceAll("", "", "zzz")    = "zzz"
6466      * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
6467      * StringUtils.replaceAll("", ".+", "zzz")  = ""
6468      * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
6469      * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
6470      * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6471      * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
6472      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6473      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6474      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6475      * }</pre>
6476      *
6477      * @param text  text to search and replace in, may be null
6478      * @param regex  the regular expression to which this string is to be matched
6479      * @param replacement  the string to be substituted for each match
6480      * @return  the text with any replacements processed,
6481      *              {@code null} if null String input
6482      *
6483      * @throws  java.util.regex.PatternSyntaxException
6484      *              if the regular expression's syntax is invalid
6485      *
6486      * @see #replacePattern(String, String, String)
6487      * @see String#replaceAll(String, String)
6488      * @see java.util.regex.Pattern
6489      * @see java.util.regex.Pattern#DOTALL
6490      * @since 3.5
6491      *
6492      * @deprecated Moved to RegExUtils.
6493      */
6494     @Deprecated
6495     public static String replaceAll(final String text, final String regex, final String replacement) {
6496         return RegExUtils.replaceAll(text, regex, replacement);
6497     }
6498 
6499     /**
6500      * Replaces all occurrences of a character in a String with another.
6501      * This is a null-safe version of {@link String#replace(char, char)}.
6502      *
6503      * <p>A {@code null} string input returns {@code null}.
6504      * An empty ("") string input returns an empty string.</p>
6505      *
6506      * <pre>
6507      * StringUtils.replaceChars(null, *, *)        = null
6508      * StringUtils.replaceChars("", *, *)          = ""
6509      * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6510      * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6511      * </pre>
6512      *
6513      * @param str  String to replace characters in, may be null
6514      * @param searchChar  the character to search for, may be null
6515      * @param replaceChar  the character to replace, may be null
6516      * @return modified String, {@code null} if null string input
6517      * @since 2.0
6518      */
6519     public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6520         if (str == null) {
6521             return null;
6522         }
6523         return str.replace(searchChar, replaceChar);
6524     }
6525 
6526     /**
6527      * Replaces multiple characters in a String in one go.
6528      * This method can also be used to delete characters.
6529      *
6530      * <p>For example:<br>
6531      * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
6532      *
6533      * <p>A {@code null} string input returns {@code null}.
6534      * An empty ("") string input returns an empty string.
6535      * A null or empty set of search characters returns the input string.</p>
6536      *
6537      * <p>The length of the search characters should normally equal the length
6538      * of the replace characters.
6539      * If the search characters is longer, then the extra search characters
6540      * are deleted.
6541      * If the search characters is shorter, then the extra replace characters
6542      * are ignored.</p>
6543      *
6544      * <pre>
6545      * StringUtils.replaceChars(null, *, *)           = null
6546      * StringUtils.replaceChars("", *, *)             = ""
6547      * StringUtils.replaceChars("abc", null, *)       = "abc"
6548      * StringUtils.replaceChars("abc", "", *)         = "abc"
6549      * StringUtils.replaceChars("abc", "b", null)     = "ac"
6550      * StringUtils.replaceChars("abc", "b", "")       = "ac"
6551      * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6552      * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6553      * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6554      * </pre>
6555      *
6556      * @param str  String to replace characters in, may be null
6557      * @param searchChars  a set of characters to search for, may be null
6558      * @param replaceChars  a set of characters to replace, may be null
6559      * @return modified String, {@code null} if null string input
6560      * @since 2.0
6561      */
6562     public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6563         if (isEmpty(str) || isEmpty(searchChars)) {
6564             return str;
6565         }
6566         if (replaceChars == null) {
6567             replaceChars = EMPTY;
6568         }
6569         boolean modified = false;
6570         final int replaceCharsLength = replaceChars.length();
6571         final int strLength = str.length();
6572         final StringBuilder buf = new StringBuilder(strLength);
6573         for (int i = 0; i < strLength; i++) {
6574             final char ch = str.charAt(i);
6575             final int index = searchChars.indexOf(ch);
6576             if (index >= 0) {
6577                 modified = true;
6578                 if (index < replaceCharsLength) {
6579                     buf.append(replaceChars.charAt(index));
6580                 }
6581             } else {
6582                 buf.append(ch);
6583             }
6584         }
6585         if (modified) {
6586             return buf.toString();
6587         }
6588         return str;
6589     }
6590 
6591     /**
6592      * Replaces all occurrences of Strings within another String.
6593      *
6594      * <p>
6595      * A {@code null} reference passed to this method is a no-op, or if
6596      * any "search string" or "string to replace" is null, that replace will be
6597      * ignored. This will not repeat. For repeating replaces, call the
6598      * overloaded method.
6599      * </p>
6600      *
6601      * <pre>
6602      *  StringUtils.replaceEach(null, *, *)        = null
6603      *  StringUtils.replaceEach("", *, *)          = ""
6604      *  StringUtils.replaceEach("aba", null, null) = "aba"
6605      *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
6606      *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
6607      *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
6608      *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
6609      *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
6610      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6611      *  (example of how it does not repeat)
6612      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6613      * </pre>
6614      *
6615      * @param text
6616      *            text to search and replace in, no-op if null
6617      * @param searchList
6618      *            the Strings to search for, no-op if null
6619      * @param replacementList
6620      *            the Strings to replace them with, no-op if null
6621      * @return the text with any replacements processed, {@code null} if
6622      *         null String input
6623      * @throws IllegalArgumentException
6624      *             if the lengths of the arrays are not the same (null is ok,
6625      *             and/or size 0)
6626      * @since 2.4
6627      */
6628     public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6629         return replaceEach(text, searchList, replacementList, false, 0);
6630     }
6631 
6632     /**
6633      * Replace all occurrences of Strings within another String.
6634      * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
6635      * {@link #replaceEach(String, String[], String[])}
6636      *
6637      * <p>
6638      * A {@code null} reference passed to this method is a no-op, or if
6639      * any "search string" or "string to replace" is null, that replace will be
6640      * ignored.
6641      * </p>
6642      *
6643      * <pre>
6644      *  StringUtils.replaceEach(null, *, *, *, *) = null
6645      *  StringUtils.replaceEach("", *, *, *, *) = ""
6646      *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
6647      *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
6648      *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
6649      *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
6650      *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
6651      *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
6652      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
6653      *  (example of how it repeats)
6654      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6655      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
6656      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
6657      * </pre>
6658      *
6659      * @param text
6660      *            text to search and replace in, no-op if null
6661      * @param searchList
6662      *            the Strings to search for, no-op if null
6663      * @param replacementList
6664      *            the Strings to replace them with, no-op if null
6665      * @param repeat if true, then replace repeatedly
6666      *       until there are no more possible replacements or timeToLive < 0
6667      * @param timeToLive
6668      *            if less than 0 then there is a circular reference and endless
6669      *            loop
6670      * @return the text with any replacements processed, {@code null} if
6671      *         null String input
6672      * @throws IllegalStateException
6673      *             if the search is repeating and there is an endless loop due
6674      *             to outputs of one being inputs to another
6675      * @throws IllegalArgumentException
6676      *             if the lengths of the arrays are not the same (null is ok,
6677      *             and/or size 0)
6678      * @since 2.4
6679      */
6680     private static String replaceEach(
6681             final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6682 
6683         // mchyzer Performance note: This creates very few new objects (one major goal)
6684         // let me know if there are performance requests, we can create a harness to measure
6685 
6686         // if recursing, this shouldn't be less than 0
6687         if (timeToLive < 0) {
6688             final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
6689             final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
6690             searchSet.retainAll(replacementSet);
6691             if (!searchSet.isEmpty()) {
6692                 throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6693                         "output of one loop is the input of another");
6694             }
6695         }
6696 
6697         if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || ArrayUtils.isNotEmpty(searchList) && timeToLive == -1) {
6698             return text;
6699         }
6700 
6701         final int searchLength = searchList.length;
6702         final int replacementLength = replacementList.length;
6703 
6704         // make sure lengths are ok, these need to be equal
6705         if (searchLength != replacementLength) {
6706             throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6707                 + searchLength
6708                 + " vs "
6709                 + replacementLength);
6710         }
6711 
6712         // keep track of which still have matches
6713         final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6714 
6715         // index on index that the match was found
6716         int textIndex = -1;
6717         int replaceIndex = -1;
6718         int tempIndex;
6719 
6720         // index of replace array that will replace the search string found
6721         // NOTE: logic duplicated below START
6722         for (int i = 0; i < searchLength; i++) {
6723             if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6724                 continue;
6725             }
6726             tempIndex = text.indexOf(searchList[i]);
6727 
6728             // see if we need to keep searching for this
6729             if (tempIndex == -1) {
6730                 noMoreMatchesForReplIndex[i] = true;
6731             } else if (textIndex == -1 || tempIndex < textIndex) {
6732                 textIndex = tempIndex;
6733                 replaceIndex = i;
6734             }
6735         }
6736         // NOTE: logic mostly below END
6737 
6738         // no search strings found, we are done
6739         if (textIndex == -1) {
6740             return text;
6741         }
6742 
6743         int start = 0;
6744 
6745         // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6746         int increase = 0;
6747 
6748         // count the replacement text elements that are larger than their corresponding text being replaced
6749         for (int i = 0; i < searchList.length; i++) {
6750             if (searchList[i] == null || replacementList[i] == null) {
6751                 continue;
6752             }
6753             final int greater = replacementList[i].length() - searchList[i].length();
6754             if (greater > 0) {
6755                 increase += 3 * greater; // assume 3 matches
6756             }
6757         }
6758         // have upper-bound at 20% increase, then let Java take over
6759         increase = Math.min(increase, text.length() / 5);
6760 
6761         final StringBuilder buf = new StringBuilder(text.length() + increase);
6762 
6763         while (textIndex != -1) {
6764 
6765             for (int i = start; i < textIndex; i++) {
6766                 buf.append(text.charAt(i));
6767             }
6768             buf.append(replacementList[replaceIndex]);
6769 
6770             start = textIndex + searchList[replaceIndex].length();
6771 
6772             textIndex = -1;
6773             replaceIndex = -1;
6774             // find the next earliest match
6775             // NOTE: logic mostly duplicated above START
6776             for (int i = 0; i < searchLength; i++) {
6777                 if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6778                     continue;
6779                 }
6780                 tempIndex = text.indexOf(searchList[i], start);
6781 
6782                 // see if we need to keep searching for this
6783                 if (tempIndex == -1) {
6784                     noMoreMatchesForReplIndex[i] = true;
6785                 } else if (textIndex == -1 || tempIndex < textIndex) {
6786                     textIndex = tempIndex;
6787                     replaceIndex = i;
6788                 }
6789             }
6790             // NOTE: logic duplicated above END
6791 
6792         }
6793         final int textLength = text.length();
6794         for (int i = start; i < textLength; i++) {
6795             buf.append(text.charAt(i));
6796         }
6797         final String result = buf.toString();
6798         if (!repeat) {
6799             return result;
6800         }
6801 
6802         return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6803     }
6804 
6805     /**
6806      * Replaces all occurrences of Strings within another String.
6807      *
6808      * <p>
6809      * A {@code null} reference passed to this method is a no-op, or if
6810      * any "search string" or "string to replace" is null, that replace will be
6811      * ignored.
6812      * </p>
6813      *
6814      * <pre>
6815      *  StringUtils.replaceEachRepeatedly(null, *, *) = null
6816      *  StringUtils.replaceEachRepeatedly("", *, *) = ""
6817      *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
6818      *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
6819      *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
6820      *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
6821      *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
6822      *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
6823      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
6824      *  (example of how it repeats)
6825      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
6826      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6827      * </pre>
6828      *
6829      * @param text
6830      *            text to search and replace in, no-op if null
6831      * @param searchList
6832      *            the Strings to search for, no-op if null
6833      * @param replacementList
6834      *            the Strings to replace them with, no-op if null
6835      * @return the text with any replacements processed, {@code null} if
6836      *         null String input
6837      * @throws IllegalStateException
6838      *             if the search is repeating and there is an endless loop due
6839      *             to outputs of one being inputs to another
6840      * @throws IllegalArgumentException
6841      *             if the lengths of the arrays are not the same (null is ok,
6842      *             and/or size 0)
6843      * @since 2.4
6844      */
6845     public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6846         return replaceEach(text, searchList, replacementList, true, ArrayUtils.getLength(searchList));
6847     }
6848 
6849     /**
6850      * Replaces the first substring of the text string that matches the given regular expression
6851      * with the given replacement.
6852      *
6853      * This method is a {@code null} safe equivalent to:
6854      * <ul>
6855      *  <li>{@code text.replaceFirst(regex, replacement)}</li>
6856      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6857      * </ul>
6858      *
6859      * <p>A {@code null} reference passed to this method is a no-op.</p>
6860      *
6861      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6862      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6863      * DOTALL is also known as single-line mode in Perl.</p>
6864      *
6865      * <pre>{@code
6866      * StringUtils.replaceFirst(null, *, *)       = null
6867      * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6868      * StringUtils.replaceFirst("any", *, null)   = "any"
6869      * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6870      * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6871      * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6872      * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6873      * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6874      * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6875      * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6876      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6877      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6878      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6879      * }</pre>
6880      *
6881      * @param text  text to search and replace in, may be null
6882      * @param regex  the regular expression to which this string is to be matched
6883      * @param replacement  the string to be substituted for the first match
6884      * @return  the text with the first replacement processed,
6885      *              {@code null} if null String input
6886      *
6887      * @throws  java.util.regex.PatternSyntaxException
6888      *              if the regular expression's syntax is invalid
6889      *
6890      * @see String#replaceFirst(String, String)
6891      * @see java.util.regex.Pattern
6892      * @see java.util.regex.Pattern#DOTALL
6893      * @since 3.5
6894      *
6895      * @deprecated Moved to RegExUtils.
6896      */
6897     @Deprecated
6898     public static String replaceFirst(final String text, final String regex, final String replacement) {
6899         return RegExUtils.replaceFirst(text, regex, replacement);
6900     }
6901 
6902     /**
6903      * Case insensitively replaces all occurrences of a String within another String.
6904      *
6905      * <p>A {@code null} reference passed to this method is a no-op.</p>
6906      *
6907      * <pre>
6908      * StringUtils.replaceIgnoreCase(null, *, *)        = null
6909      * StringUtils.replaceIgnoreCase("", *, *)          = ""
6910      * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6911      * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6912      * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6913      * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6914      * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6915      * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6916      * </pre>
6917      *
6918      * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6919      * @param text  text to search and replace in, may be null
6920      * @param searchString  the String to search for (case-insensitive), may be null
6921      * @param replacement  the String to replace it with, may be null
6922      * @return the text with any replacements processed,
6923      *  {@code null} if null String input
6924      * @since 3.5
6925      */
6926      public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6927          return replaceIgnoreCase(text, searchString, replacement, -1);
6928      }
6929 
6930     /**
6931      * Case insensitively replaces a String with another String inside a larger String,
6932      * for the first {@code max} values of the search String.
6933      *
6934      * <p>A {@code null} reference passed to this method is a no-op.</p>
6935      *
6936      * <pre>
6937      * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6938      * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6939      * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6940      * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6941      * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6942      * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6943      * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6944      * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6945      * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6946      * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6947      * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6948      * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6949      * </pre>
6950      *
6951      * @param text  text to search and replace in, may be null
6952      * @param searchString  the String to search for (case-insensitive), may be null
6953      * @param replacement  the String to replace it with, may be null
6954      * @param max  maximum number of values to replace, or {@code -1} if no maximum
6955      * @return the text with any replacements processed,
6956      *  {@code null} if null String input
6957      * @since 3.5
6958      */
6959     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6960         return replace(text, searchString, replacement, max, true);
6961     }
6962 
6963     /**
6964      * Replaces a String with another String inside a larger String, once.
6965      *
6966      * <p>A {@code null} reference passed to this method is a no-op.</p>
6967      *
6968      * <pre>
6969      * StringUtils.replaceOnce(null, *, *)        = null
6970      * StringUtils.replaceOnce("", *, *)          = ""
6971      * StringUtils.replaceOnce("any", null, *)    = "any"
6972      * StringUtils.replaceOnce("any", *, null)    = "any"
6973      * StringUtils.replaceOnce("any", "", *)      = "any"
6974      * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6975      * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6976      * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6977      * </pre>
6978      *
6979      * @see #replace(String text, String searchString, String replacement, int max)
6980      * @param text  text to search and replace in, may be null
6981      * @param searchString  the String to search for, may be null
6982      * @param replacement  the String to replace with, may be null
6983      * @return the text with any replacements processed,
6984      *  {@code null} if null String input
6985      */
6986     public static String replaceOnce(final String text, final String searchString, final String replacement) {
6987         return replace(text, searchString, replacement, 1);
6988     }
6989 
6990     /**
6991      * Case insensitively replaces a String with another String inside a larger String, once.
6992      *
6993      * <p>A {@code null} reference passed to this method is a no-op.</p>
6994      *
6995      * <pre>
6996      * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6997      * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6998      * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6999      * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
7000      * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
7001      * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
7002      * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
7003      * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
7004      * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
7005      * </pre>
7006      *
7007      * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
7008      * @param text  text to search and replace in, may be null
7009      * @param searchString  the String to search for (case-insensitive), may be null
7010      * @param replacement  the String to replace with, may be null
7011      * @return the text with any replacements processed,
7012      *  {@code null} if null String input
7013      * @since 3.5
7014      */
7015     public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
7016         return replaceIgnoreCase(text, searchString, replacement, 1);
7017     }
7018 
7019     /**
7020      * Replaces each substring of the source String that matches the given regular expression with the given
7021      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
7022      *
7023      * This call is a {@code null} safe equivalent to:
7024      * <ul>
7025      * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
7026      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
7027      * </ul>
7028      *
7029      * <p>A {@code null} reference passed to this method is a no-op.</p>
7030      *
7031      * <pre>{@code
7032      * StringUtils.replacePattern(null, *, *)       = null
7033      * StringUtils.replacePattern("any", (String) null, *)   = "any"
7034      * StringUtils.replacePattern("any", *, null)   = "any"
7035      * StringUtils.replacePattern("", "", "zzz")    = "zzz"
7036      * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
7037      * StringUtils.replacePattern("", ".+", "zzz")  = ""
7038      * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
7039      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
7040      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
7041      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
7042      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
7043      * }</pre>
7044      *
7045      * @param source
7046      *            the source string
7047      * @param regex
7048      *            the regular expression to which this string is to be matched
7049      * @param replacement
7050      *            the string to be substituted for each match
7051      * @return The resulting {@link String}
7052      * @see #replaceAll(String, String, String)
7053      * @see String#replaceAll(String, String)
7054      * @see Pattern#DOTALL
7055      * @since 3.2
7056      * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
7057      *
7058      * @deprecated Moved to RegExUtils.
7059      */
7060     @Deprecated
7061     public static String replacePattern(final String source, final String regex, final String replacement) {
7062         return RegExUtils.replacePattern(source, regex, replacement);
7063     }
7064 
7065     /**
7066      * Reverses a String as per {@link StringBuilder#reverse()}.
7067      *
7068      * <p>A {@code null} String returns {@code null}.</p>
7069      *
7070      * <pre>
7071      * StringUtils.reverse(null)  = null
7072      * StringUtils.reverse("")    = ""
7073      * StringUtils.reverse("bat") = "tab"
7074      * </pre>
7075      *
7076      * @param str  the String to reverse, may be null
7077      * @return the reversed String, {@code null} if null String input
7078      */
7079     public static String reverse(final String str) {
7080         if (str == null) {
7081             return null;
7082         }
7083         return new StringBuilder(str).reverse().toString();
7084     }
7085 
7086     /**
7087      * Reverses a String that is delimited by a specific character.
7088      *
7089      * <p>The Strings between the delimiters are not reversed.
7090      * Thus java.lang.String becomes String.lang.java (if the delimiter
7091      * is {@code '.'}).</p>
7092      *
7093      * <pre>
7094      * StringUtils.reverseDelimited(null, *)      = null
7095      * StringUtils.reverseDelimited("", *)        = ""
7096      * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7097      * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7098      * </pre>
7099      *
7100      * @param str  the String to reverse, may be null
7101      * @param separatorChar  the separator character to use
7102      * @return the reversed String, {@code null} if null String input
7103      * @since 2.0
7104      */
7105     public static String reverseDelimited(final String str, final char separatorChar) {
7106         final String[] strs = split(str, separatorChar);
7107         ArrayUtils.reverse(strs);
7108         return join(strs, separatorChar);
7109     }
7110 
7111     /**
7112      * Gets the rightmost {@code len} characters of a String.
7113      *
7114      * <p>If {@code len} characters are not available, or the String
7115      * is {@code null}, the String will be returned without an
7116      * an exception. An empty String is returned if len is negative.</p>
7117      *
7118      * <pre>
7119      * StringUtils.right(null, *)    = null
7120      * StringUtils.right(*, -ve)     = ""
7121      * StringUtils.right("", *)      = ""
7122      * StringUtils.right("abc", 0)   = ""
7123      * StringUtils.right("abc", 2)   = "bc"
7124      * StringUtils.right("abc", 4)   = "abc"
7125      * </pre>
7126      *
7127      * @param str  the String to get the rightmost characters from, may be null
7128      * @param len  the length of the required String
7129      * @return the rightmost characters, {@code null} if null String input
7130      */
7131     public static String right(final String str, final int len) {
7132         if (str == null) {
7133             return null;
7134         }
7135         if (len < 0) {
7136             return EMPTY;
7137         }
7138         if (str.length() <= len) {
7139             return str;
7140         }
7141         return str.substring(str.length() - len);
7142     }
7143 
7144     /**
7145      * Right pad a String with spaces (' ').
7146      *
7147      * <p>The String is padded to the size of {@code size}.</p>
7148      *
7149      * <pre>
7150      * StringUtils.rightPad(null, *)   = null
7151      * StringUtils.rightPad("", 3)     = "   "
7152      * StringUtils.rightPad("bat", 3)  = "bat"
7153      * StringUtils.rightPad("bat", 5)  = "bat  "
7154      * StringUtils.rightPad("bat", 1)  = "bat"
7155      * StringUtils.rightPad("bat", -1) = "bat"
7156      * </pre>
7157      *
7158      * @param str  the String to pad out, may be null
7159      * @param size  the size to pad to
7160      * @return right padded String or original String if no padding is necessary,
7161      *  {@code null} if null String input
7162      */
7163     public static String rightPad(final String str, final int size) {
7164         return rightPad(str, size, ' ');
7165     }
7166 
7167     /**
7168      * Right pad a String with a specified character.
7169      *
7170      * <p>The String is padded to the size of {@code size}.</p>
7171      *
7172      * <pre>
7173      * StringUtils.rightPad(null, *, *)     = null
7174      * StringUtils.rightPad("", 3, 'z')     = "zzz"
7175      * StringUtils.rightPad("bat", 3, 'z')  = "bat"
7176      * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
7177      * StringUtils.rightPad("bat", 1, 'z')  = "bat"
7178      * StringUtils.rightPad("bat", -1, 'z') = "bat"
7179      * </pre>
7180      *
7181      * @param str  the String to pad out, may be null
7182      * @param size  the size to pad to
7183      * @param padChar  the character to pad with
7184      * @return right padded String or original String if no padding is necessary,
7185      *  {@code null} if null String input
7186      * @since 2.0
7187      */
7188     public static String rightPad(final String str, final int size, final char padChar) {
7189         if (str == null) {
7190             return null;
7191         }
7192         final int pads = size - str.length();
7193         if (pads <= 0) {
7194             return str; // returns original String when possible
7195         }
7196         if (pads > PAD_LIMIT) {
7197             return rightPad(str, size, String.valueOf(padChar));
7198         }
7199         return str.concat(repeat(padChar, pads));
7200     }
7201 
7202     /**
7203      * Right pad a String with a specified String.
7204      *
7205      * <p>The String is padded to the size of {@code size}.</p>
7206      *
7207      * <pre>
7208      * StringUtils.rightPad(null, *, *)      = null
7209      * StringUtils.rightPad("", 3, "z")      = "zzz"
7210      * StringUtils.rightPad("bat", 3, "yz")  = "bat"
7211      * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
7212      * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
7213      * StringUtils.rightPad("bat", 1, "yz")  = "bat"
7214      * StringUtils.rightPad("bat", -1, "yz") = "bat"
7215      * StringUtils.rightPad("bat", 5, null)  = "bat  "
7216      * StringUtils.rightPad("bat", 5, "")    = "bat  "
7217      * </pre>
7218      *
7219      * @param str  the String to pad out, may be null
7220      * @param size  the size to pad to
7221      * @param padStr  the String to pad with, null or empty treated as single space
7222      * @return right padded String or original String if no padding is necessary,
7223      *  {@code null} if null String input
7224      */
7225     public static String rightPad(final String str, final int size, String padStr) {
7226         if (str == null) {
7227             return null;
7228         }
7229         if (isEmpty(padStr)) {
7230             padStr = SPACE;
7231         }
7232         final int padLen = padStr.length();
7233         final int strLen = str.length();
7234         final int pads = size - strLen;
7235         if (pads <= 0) {
7236             return str; // returns original String when possible
7237         }
7238         if (padLen == 1 && pads <= PAD_LIMIT) {
7239             return rightPad(str, size, padStr.charAt(0));
7240         }
7241 
7242         if (pads == padLen) {
7243             return str.concat(padStr);
7244         }
7245         if (pads < padLen) {
7246             return str.concat(padStr.substring(0, pads));
7247         }
7248         final char[] padding = new char[pads];
7249         final char[] padChars = padStr.toCharArray();
7250         for (int i = 0; i < pads; i++) {
7251             padding[i] = padChars[i % padLen];
7252         }
7253         return str.concat(new String(padding));
7254     }
7255 
7256     /**
7257      * Rotate (circular shift) a String of {@code shift} characters.
7258      * <ul>
7259      *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7260      *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7261      * </ul>
7262      *
7263      * <pre>
7264      * StringUtils.rotate(null, *)        = null
7265      * StringUtils.rotate("", *)          = ""
7266      * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7267      * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7268      * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7269      * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7270      * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7271      * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7272      * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7273      * </pre>
7274      *
7275      * @param str  the String to rotate, may be null
7276      * @param shift  number of time to shift (positive : right shift, negative : left shift)
7277      * @return the rotated String,
7278      *          or the original String if {@code shift == 0},
7279      *          or {@code null} if null String input
7280      * @since 3.5
7281      */
7282     public static String rotate(final String str, final int shift) {
7283         if (str == null) {
7284             return null;
7285         }
7286 
7287         final int strLen = str.length();
7288         if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7289             return str;
7290         }
7291 
7292         final StringBuilder builder = new StringBuilder(strLen);
7293         final int offset = - (shift % strLen);
7294         builder.append(substring(str, offset));
7295         builder.append(substring(str, 0, offset));
7296         return builder.toString();
7297     }
7298 
7299     /**
7300      * Splits the provided text into an array, using whitespace as the
7301      * separator.
7302      * Whitespace is defined by {@link Character#isWhitespace(char)}.
7303      *
7304      * <p>The separator is not included in the returned String array.
7305      * Adjacent separators are treated as one separator.
7306      * For more control over the split use the StrTokenizer class.</p>
7307      *
7308      * <p>A {@code null} input String returns {@code null}.</p>
7309      *
7310      * <pre>
7311      * StringUtils.split(null)       = null
7312      * StringUtils.split("")         = []
7313      * StringUtils.split("abc def")  = ["abc", "def"]
7314      * StringUtils.split("abc  def") = ["abc", "def"]
7315      * StringUtils.split(" abc ")    = ["abc"]
7316      * </pre>
7317      *
7318      * @param str  the String to parse, may be null
7319      * @return an array of parsed Strings, {@code null} if null String input
7320      */
7321     public static String[] split(final String str) {
7322         return split(str, null, -1);
7323     }
7324 
7325     /**
7326      * Splits the provided text into an array, separator specified.
7327      * This is an alternative to using StringTokenizer.
7328      *
7329      * <p>The separator is not included in the returned String array.
7330      * Adjacent separators are treated as one separator.
7331      * For more control over the split use the StrTokenizer class.</p>
7332      *
7333      * <p>A {@code null} input String returns {@code null}.</p>
7334      *
7335      * <pre>
7336      * StringUtils.split(null, *)         = null
7337      * StringUtils.split("", *)           = []
7338      * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7339      * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7340      * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7341      * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7342      * </pre>
7343      *
7344      * @param str  the String to parse, may be null
7345      * @param separatorChar  the character used as the delimiter
7346      * @return an array of parsed Strings, {@code null} if null String input
7347      * @since 2.0
7348      */
7349     public static String[] split(final String str, final char separatorChar) {
7350         return splitWorker(str, separatorChar, false);
7351     }
7352 
7353     /**
7354      * Splits the provided text into an array, separators specified.
7355      * This is an alternative to using StringTokenizer.
7356      *
7357      * <p>The separator is not included in the returned String array.
7358      * Adjacent separators are treated as one separator.
7359      * For more control over the split use the StrTokenizer class.</p>
7360      *
7361      * <p>A {@code null} input String returns {@code null}.
7362      * A {@code null} separatorChars splits on whitespace.</p>
7363      *
7364      * <pre>
7365      * StringUtils.split(null, *)         = null
7366      * StringUtils.split("", *)           = []
7367      * StringUtils.split("abc def", null) = ["abc", "def"]
7368      * StringUtils.split("abc def", " ")  = ["abc", "def"]
7369      * StringUtils.split("abc  def", " ") = ["abc", "def"]
7370      * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7371      * </pre>
7372      *
7373      * @param str  the String to parse, may be null
7374      * @param separatorChars  the characters used as the delimiters,
7375      *  {@code null} splits on whitespace
7376      * @return an array of parsed Strings, {@code null} if null String input
7377      */
7378     public static String[] split(final String str, final String separatorChars) {
7379         return splitWorker(str, separatorChars, -1, false);
7380     }
7381 
7382     /**
7383      * Splits the provided text into an array with a maximum length,
7384      * separators specified.
7385      *
7386      * <p>The separator is not included in the returned String array.
7387      * Adjacent separators are treated as one separator.</p>
7388      *
7389      * <p>A {@code null} input String returns {@code null}.
7390      * A {@code null} separatorChars splits on whitespace.</p>
7391      *
7392      * <p>If more than {@code max} delimited substrings are found, the last
7393      * returned string includes all characters after the first {@code max - 1}
7394      * returned strings (including separator characters).</p>
7395      *
7396      * <pre>
7397      * StringUtils.split(null, *, *)            = null
7398      * StringUtils.split("", *, *)              = []
7399      * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7400      * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7401      * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7402      * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7403      * </pre>
7404      *
7405      * @param str  the String to parse, may be null
7406      * @param separatorChars  the characters used as the delimiters,
7407      *  {@code null} splits on whitespace
7408      * @param max  the maximum number of elements to include in the
7409      *  array. A zero or negative value implies no limit
7410      * @return an array of parsed Strings, {@code null} if null String input
7411      */
7412     public static String[] split(final String str, final String separatorChars, final int max) {
7413         return splitWorker(str, separatorChars, max, false);
7414     }
7415 
7416     /**
7417      * Splits a String by Character type as returned by
7418      * {@code java.lang.Character.getType(char)}. Groups of contiguous
7419      * characters of the same type are returned as complete tokens.
7420      * <pre>
7421      * StringUtils.splitByCharacterType(null)         = null
7422      * StringUtils.splitByCharacterType("")           = []
7423      * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7424      * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7425      * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7426      * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7427      * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7428      * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7429      * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7430      * </pre>
7431      * @param str the String to split, may be {@code null}
7432      * @return an array of parsed Strings, {@code null} if null String input
7433      * @since 2.4
7434      */
7435     public static String[] splitByCharacterType(final String str) {
7436         return splitByCharacterType(str, false);
7437     }
7438 
7439     /**
7440      * <p>Splits a String by Character type as returned by
7441      * {@code java.lang.Character.getType(char)}. Groups of contiguous
7442      * characters of the same type are returned as complete tokens, with the
7443      * following exception: if {@code camelCase} is {@code true},
7444      * the character of type {@code Character.UPPERCASE_LETTER}, if any,
7445      * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
7446      * will belong to the following token rather than to the preceding, if any,
7447      * {@code Character.UPPERCASE_LETTER} token.
7448      * @param str the String to split, may be {@code null}
7449      * @param camelCase whether to use so-called "camel-case" for letter types
7450      * @return an array of parsed Strings, {@code null} if null String input
7451      * @since 2.4
7452      */
7453     private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7454         if (str == null) {
7455             return null;
7456         }
7457         if (str.isEmpty()) {
7458             return ArrayUtils.EMPTY_STRING_ARRAY;
7459         }
7460         final char[] c = str.toCharArray();
7461         final List<String> list = new ArrayList<>();
7462         int tokenStart = 0;
7463         int currentType = Character.getType(c[tokenStart]);
7464         for (int pos = tokenStart + 1; pos < c.length; pos++) {
7465             final int type = Character.getType(c[pos]);
7466             if (type == currentType) {
7467                 continue;
7468             }
7469             if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7470                 final int newTokenStart = pos - 1;
7471                 if (newTokenStart != tokenStart) {
7472                     list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7473                     tokenStart = newTokenStart;
7474                 }
7475             } else {
7476                 list.add(new String(c, tokenStart, pos - tokenStart));
7477                 tokenStart = pos;
7478             }
7479             currentType = type;
7480         }
7481         list.add(new String(c, tokenStart, c.length - tokenStart));
7482         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7483     }
7484 
7485     /**
7486      * <p>Splits a String by Character type as returned by
7487      * {@code java.lang.Character.getType(char)}. Groups of contiguous
7488      * characters of the same type are returned as complete tokens, with the
7489      * following exception: the character of type
7490      * {@code Character.UPPERCASE_LETTER}, if any, immediately
7491      * preceding a token of type {@code Character.LOWERCASE_LETTER}
7492      * will belong to the following token rather than to the preceding, if any,
7493      * {@code Character.UPPERCASE_LETTER} token.
7494      * <pre>
7495      * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7496      * StringUtils.splitByCharacterTypeCamelCase("")           = []
7497      * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7498      * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7499      * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7500      * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7501      * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7502      * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7503      * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7504      * </pre>
7505      * @param str the String to split, may be {@code null}
7506      * @return an array of parsed Strings, {@code null} if null String input
7507      * @since 2.4
7508      */
7509     public static String[] splitByCharacterTypeCamelCase(final String str) {
7510         return splitByCharacterType(str, true);
7511     }
7512 
7513     /**
7514      * <p>Splits the provided text into an array, separator string specified.
7515      *
7516      * <p>The separator(s) will not be included in the returned String array.
7517      * Adjacent separators are treated as one separator.</p>
7518      *
7519      * <p>A {@code null} input String returns {@code null}.
7520      * A {@code null} separator splits on whitespace.</p>
7521      *
7522      * <pre>
7523      * StringUtils.splitByWholeSeparator(null, *)               = null
7524      * StringUtils.splitByWholeSeparator("", *)                 = []
7525      * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7526      * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7527      * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7528      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7529      * </pre>
7530      *
7531      * @param str  the String to parse, may be null
7532      * @param separator  String containing the String to be used as a delimiter,
7533      *  {@code null} splits on whitespace
7534      * @return an array of parsed Strings, {@code null} if null String was input
7535      */
7536     public static String[] splitByWholeSeparator(final String str, final String separator) {
7537         return splitByWholeSeparatorWorker(str, separator, -1, false);
7538     }
7539 
7540     /**
7541      * Splits the provided text into an array, separator string specified.
7542      * Returns a maximum of {@code max} substrings.
7543      *
7544      * <p>The separator(s) will not be included in the returned String array.
7545      * Adjacent separators are treated as one separator.</p>
7546      *
7547      * <p>A {@code null} input String returns {@code null}.
7548      * A {@code null} separator splits on whitespace.</p>
7549      *
7550      * <pre>
7551      * StringUtils.splitByWholeSeparator(null, *, *)               = null
7552      * StringUtils.splitByWholeSeparator("", *, *)                 = []
7553      * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7554      * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7555      * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7556      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7557      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7558      * </pre>
7559      *
7560      * @param str  the String to parse, may be null
7561      * @param separator  String containing the String to be used as a delimiter,
7562      *  {@code null} splits on whitespace
7563      * @param max  the maximum number of elements to include in the returned
7564      *  array. A zero or negative value implies no limit.
7565      * @return an array of parsed Strings, {@code null} if null String was input
7566      */
7567     public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
7568         return splitByWholeSeparatorWorker(str, separator, max, false);
7569     }
7570 
7571     /**
7572      * Splits the provided text into an array, separator string specified.
7573      *
7574      * <p>The separator is not included in the returned String array.
7575      * Adjacent separators are treated as separators for empty tokens.
7576      * For more control over the split use the StrTokenizer class.</p>
7577      *
7578      * <p>A {@code null} input String returns {@code null}.
7579      * A {@code null} separator splits on whitespace.</p>
7580      *
7581      * <pre>
7582      * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7583      * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7584      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7585      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7586      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7587      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7588      * </pre>
7589      *
7590      * @param str  the String to parse, may be null
7591      * @param separator  String containing the String to be used as a delimiter,
7592      *  {@code null} splits on whitespace
7593      * @return an array of parsed Strings, {@code null} if null String was input
7594      * @since 2.4
7595      */
7596     public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7597         return splitByWholeSeparatorWorker(str, separator, -1, true);
7598     }
7599 
7600     /**
7601      * Splits the provided text into an array, separator string specified.
7602      * Returns a maximum of {@code max} substrings.
7603      *
7604      * <p>The separator is not included in the returned String array.
7605      * Adjacent separators are treated as separators for empty tokens.
7606      * For more control over the split use the StrTokenizer class.</p>
7607      *
7608      * <p>A {@code null} input String returns {@code null}.
7609      * A {@code null} separator splits on whitespace.</p>
7610      *
7611      * <pre>
7612      * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7613      * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7614      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7615      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7616      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7617      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7618      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7619      * </pre>
7620      *
7621      * @param str  the String to parse, may be null
7622      * @param separator  String containing the String to be used as a delimiter,
7623      *  {@code null} splits on whitespace
7624      * @param max  the maximum number of elements to include in the returned
7625      *  array. A zero or negative value implies no limit.
7626      * @return an array of parsed Strings, {@code null} if null String was input
7627      * @since 2.4
7628      */
7629     public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7630         return splitByWholeSeparatorWorker(str, separator, max, true);
7631     }
7632 
7633     /**
7634      * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7635      *
7636      * @param str  the String to parse, may be {@code null}
7637      * @param separator  String containing the String to be used as a delimiter,
7638      *  {@code null} splits on whitespace
7639      * @param max  the maximum number of elements to include in the returned
7640      *  array. A zero or negative value implies no limit.
7641      * @param preserveAllTokens if {@code true}, adjacent separators are
7642      * treated as empty token separators; if {@code false}, adjacent
7643      * separators are treated as one separator.
7644      * @return an array of parsed Strings, {@code null} if null String input
7645      * @since 2.4
7646      */
7647     private static String[] splitByWholeSeparatorWorker(
7648             final String str, final String separator, final int max, final boolean preserveAllTokens) {
7649         if (str == null) {
7650             return null;
7651         }
7652 
7653         final int len = str.length();
7654 
7655         if (len == 0) {
7656             return ArrayUtils.EMPTY_STRING_ARRAY;
7657         }
7658 
7659         if (separator == null || EMPTY.equals(separator)) {
7660             // Split on whitespace.
7661             return splitWorker(str, null, max, preserveAllTokens);
7662         }
7663 
7664         final int separatorLength = separator.length();
7665 
7666         final ArrayList<String> substrings = new ArrayList<>();
7667         int numberOfSubstrings = 0;
7668         int beg = 0;
7669         int end = 0;
7670         while (end < len) {
7671             end = str.indexOf(separator, beg);
7672 
7673             if (end > -1) {
7674                 if (end > beg) {
7675                     numberOfSubstrings += 1;
7676 
7677                     if (numberOfSubstrings == max) {
7678                         end = len;
7679                         substrings.add(str.substring(beg));
7680                     } else {
7681                         // The following is OK, because String.substring( beg, end ) excludes
7682                         // the character at the position 'end'.
7683                         substrings.add(str.substring(beg, end));
7684 
7685                         // Set the starting point for the next search.
7686                         // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7687                         // which is the right calculation:
7688                         beg = end + separatorLength;
7689                     }
7690                 } else {
7691                     // We found a consecutive occurrence of the separator, so skip it.
7692                     if (preserveAllTokens) {
7693                         numberOfSubstrings += 1;
7694                         if (numberOfSubstrings == max) {
7695                             end = len;
7696                             substrings.add(str.substring(beg));
7697                         } else {
7698                             substrings.add(EMPTY);
7699                         }
7700                     }
7701                     beg = end + separatorLength;
7702                 }
7703             } else {
7704                 // String.substring( beg ) goes from 'beg' to the end of the String.
7705                 substrings.add(str.substring(beg));
7706                 end = len;
7707             }
7708         }
7709 
7710         return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7711     }
7712 
7713     /**
7714      * Splits the provided text into an array, using whitespace as the
7715      * separator, preserving all tokens, including empty tokens created by
7716      * adjacent separators. This is an alternative to using StringTokenizer.
7717      * Whitespace is defined by {@link Character#isWhitespace(char)}.
7718      *
7719      * <p>The separator is not included in the returned String array.
7720      * Adjacent separators are treated as separators for empty tokens.
7721      * For more control over the split use the StrTokenizer class.</p>
7722      *
7723      * <p>A {@code null} input String returns {@code null}.</p>
7724      *
7725      * <pre>
7726      * StringUtils.splitPreserveAllTokens(null)       = null
7727      * StringUtils.splitPreserveAllTokens("")         = []
7728      * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7729      * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7730      * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7731      * </pre>
7732      *
7733      * @param str  the String to parse, may be {@code null}
7734      * @return an array of parsed Strings, {@code null} if null String input
7735      * @since 2.1
7736      */
7737     public static String[] splitPreserveAllTokens(final String str) {
7738         return splitWorker(str, null, -1, true);
7739     }
7740 
7741     /**
7742      * Splits the provided text into an array, separator specified,
7743      * preserving all tokens, including empty tokens created by adjacent
7744      * separators. This is an alternative to using StringTokenizer.
7745      *
7746      * <p>The separator is not included in the returned String array.
7747      * Adjacent separators are treated as separators for empty tokens.
7748      * For more control over the split use the StrTokenizer class.</p>
7749      *
7750      * <p>A {@code null} input String returns {@code null}.</p>
7751      *
7752      * <pre>
7753      * StringUtils.splitPreserveAllTokens(null, *)         = null
7754      * StringUtils.splitPreserveAllTokens("", *)           = []
7755      * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7756      * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7757      * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7758      * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7759      * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7760      * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7761      * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7762      * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7763      * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7764      * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7765      * </pre>
7766      *
7767      * @param str  the String to parse, may be {@code null}
7768      * @param separatorChar  the character used as the delimiter,
7769      *  {@code null} splits on whitespace
7770      * @return an array of parsed Strings, {@code null} if null String input
7771      * @since 2.1
7772      */
7773     public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7774         return splitWorker(str, separatorChar, true);
7775     }
7776 
7777     /**
7778      * Splits the provided text into an array, separators specified,
7779      * preserving all tokens, including empty tokens created by adjacent
7780      * separators. This is an alternative to using StringTokenizer.
7781      *
7782      * <p>The separator is not included in the returned String array.
7783      * Adjacent separators are treated as separators for empty tokens.
7784      * For more control over the split use the StrTokenizer class.</p>
7785      *
7786      * <p>A {@code null} input String returns {@code null}.
7787      * A {@code null} separatorChars splits on whitespace.</p>
7788      *
7789      * <pre>
7790      * StringUtils.splitPreserveAllTokens(null, *)           = null
7791      * StringUtils.splitPreserveAllTokens("", *)             = []
7792      * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7793      * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7794      * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7795      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7796      * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7797      * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7798      * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7799      * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7800      * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7801      * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7802      * </pre>
7803      *
7804      * @param str  the String to parse, may be {@code null}
7805      * @param separatorChars  the characters used as the delimiters,
7806      *  {@code null} splits on whitespace
7807      * @return an array of parsed Strings, {@code null} if null String input
7808      * @since 2.1
7809      */
7810     public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7811         return splitWorker(str, separatorChars, -1, true);
7812     }
7813 
7814     /**
7815      * Splits the provided text into an array with a maximum length,
7816      * separators specified, preserving all tokens, including empty tokens
7817      * created by adjacent separators.
7818      *
7819      * <p>The separator is not included in the returned String array.
7820      * Adjacent separators are treated as separators for empty tokens.
7821      * Adjacent separators are treated as one separator.</p>
7822      *
7823      * <p>A {@code null} input String returns {@code null}.
7824      * A {@code null} separatorChars splits on whitespace.</p>
7825      *
7826      * <p>If more than {@code max} delimited substrings are found, the last
7827      * returned string includes all characters after the first {@code max - 1}
7828      * returned strings (including separator characters).</p>
7829      *
7830      * <pre>
7831      * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7832      * StringUtils.splitPreserveAllTokens("", *, *)              = []
7833      * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7834      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7835      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7836      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7837      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7838      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7839      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7840      * </pre>
7841      *
7842      * @param str  the String to parse, may be {@code null}
7843      * @param separatorChars  the characters used as the delimiters,
7844      *  {@code null} splits on whitespace
7845      * @param max  the maximum number of elements to include in the
7846      *  array. A zero or negative value implies no limit
7847      * @return an array of parsed Strings, {@code null} if null String input
7848      * @since 2.1
7849      */
7850     public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7851         return splitWorker(str, separatorChars, max, true);
7852     }
7853 
7854     /**
7855      * Performs the logic for the {@code split} and
7856      * {@code splitPreserveAllTokens} methods that do not return a
7857      * maximum array length.
7858      *
7859      * @param str  the String to parse, may be {@code null}
7860      * @param separatorChar the separate character
7861      * @param preserveAllTokens if {@code true}, adjacent separators are
7862      * treated as empty token separators; if {@code false}, adjacent
7863      * separators are treated as one separator.
7864      * @return an array of parsed Strings, {@code null} if null String input
7865      */
7866     private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7867         // Performance tuned for 2.0 (JDK1.4)
7868         if (str == null) {
7869             return null;
7870         }
7871         final int len = str.length();
7872         if (len == 0) {
7873             return ArrayUtils.EMPTY_STRING_ARRAY;
7874         }
7875         final List<String> list = new ArrayList<>();
7876         int i = 0;
7877         int start = 0;
7878         boolean match = false;
7879         boolean lastMatch = false;
7880         while (i < len) {
7881             if (str.charAt(i) == separatorChar) {
7882                 if (match || preserveAllTokens) {
7883                     list.add(str.substring(start, i));
7884                     match = false;
7885                     lastMatch = true;
7886                 }
7887                 start = ++i;
7888                 continue;
7889             }
7890             lastMatch = false;
7891             match = true;
7892             i++;
7893         }
7894         if (match || preserveAllTokens && lastMatch) {
7895             list.add(str.substring(start, i));
7896         }
7897         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7898     }
7899 
7900     /**
7901      * Performs the logic for the {@code split} and
7902      * {@code splitPreserveAllTokens} methods that return a maximum array
7903      * length.
7904      *
7905      * @param str  the String to parse, may be {@code null}
7906      * @param separatorChars the separate character
7907      * @param max  the maximum number of elements to include in the
7908      *  array. A zero or negative value implies no limit.
7909      * @param preserveAllTokens if {@code true}, adjacent separators are
7910      * treated as empty token separators; if {@code false}, adjacent
7911      * separators are treated as one separator.
7912      * @return an array of parsed Strings, {@code null} if null String input
7913      */
7914     private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7915         // Performance tuned for 2.0 (JDK1.4)
7916         // Direct code is quicker than StringTokenizer.
7917         // Also, StringTokenizer uses isSpace() not isWhitespace()
7918 
7919         if (str == null) {
7920             return null;
7921         }
7922         final int len = str.length();
7923         if (len == 0) {
7924             return ArrayUtils.EMPTY_STRING_ARRAY;
7925         }
7926         final List<String> list = new ArrayList<>();
7927         int sizePlus1 = 1;
7928         int i = 0;
7929         int start = 0;
7930         boolean match = false;
7931         boolean lastMatch = false;
7932         if (separatorChars == null) {
7933             // Null separator means use whitespace
7934             while (i < len) {
7935                 if (Character.isWhitespace(str.charAt(i))) {
7936                     if (match || preserveAllTokens) {
7937                         lastMatch = true;
7938                         if (sizePlus1++ == max) {
7939                             i = len;
7940                             lastMatch = false;
7941                         }
7942                         list.add(str.substring(start, i));
7943                         match = false;
7944                     }
7945                     start = ++i;
7946                     continue;
7947                 }
7948                 lastMatch = false;
7949                 match = true;
7950                 i++;
7951             }
7952         } else if (separatorChars.length() == 1) {
7953             // Optimise 1 character case
7954             final char sep = separatorChars.charAt(0);
7955             while (i < len) {
7956                 if (str.charAt(i) == sep) {
7957                     if (match || preserveAllTokens) {
7958                         lastMatch = true;
7959                         if (sizePlus1++ == max) {
7960                             i = len;
7961                             lastMatch = false;
7962                         }
7963                         list.add(str.substring(start, i));
7964                         match = false;
7965                     }
7966                     start = ++i;
7967                     continue;
7968                 }
7969                 lastMatch = false;
7970                 match = true;
7971                 i++;
7972             }
7973         } else {
7974             // standard case
7975             while (i < len) {
7976                 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7977                     if (match || preserveAllTokens) {
7978                         lastMatch = true;
7979                         if (sizePlus1++ == max) {
7980                             i = len;
7981                             lastMatch = false;
7982                         }
7983                         list.add(str.substring(start, i));
7984                         match = false;
7985                     }
7986                     start = ++i;
7987                     continue;
7988                 }
7989                 lastMatch = false;
7990                 match = true;
7991                 i++;
7992             }
7993         }
7994         if (match || preserveAllTokens && lastMatch) {
7995             list.add(str.substring(start, i));
7996         }
7997         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7998     }
7999 
8000     /**
8001      * Check if a CharSequence starts with a specified prefix.
8002      *
8003      * <p>{@code null}s are handled without exceptions. Two {@code null}
8004      * references are considered to be equal. The comparison is case-sensitive.</p>
8005      *
8006      * <pre>
8007      * StringUtils.startsWith(null, null)      = true
8008      * StringUtils.startsWith(null, "abc")     = false
8009      * StringUtils.startsWith("abcdef", null)  = false
8010      * StringUtils.startsWith("abcdef", "abc") = true
8011      * StringUtils.startsWith("ABCDEF", "abc") = false
8012      * </pre>
8013      *
8014      * @see String#startsWith(String)
8015      * @param str  the CharSequence to check, may be null
8016      * @param prefix the prefix to find, may be null
8017      * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
8018      *  both {@code null}
8019      * @since 2.4
8020      * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8021      */
8022     public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8023         return startsWith(str, prefix, false);
8024     }
8025 
8026     /**
8027      * Check if a CharSequence starts with a specified prefix (optionally case-insensitive).
8028      *
8029      * @see String#startsWith(String)
8030      * @param str  the CharSequence to check, may be null
8031      * @param prefix the prefix to find, may be null
8032      * @param ignoreCase indicates whether the compare should ignore case
8033      *  (case-insensitive) or not.
8034      * @return {@code true} if the CharSequence starts with the prefix or
8035      *  both {@code null}
8036      */
8037     private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8038         if (str == null || prefix == null) {
8039             return str == prefix;
8040         }
8041         // Get length once instead of twice in the unlikely case that it changes.
8042         final int preLen = prefix.length();
8043         if (preLen > str.length()) {
8044             return false;
8045         }
8046         return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen);
8047     }
8048 
8049     /**
8050      * Check if a CharSequence starts with any of the provided case-sensitive prefixes.
8051      *
8052      * <pre>
8053      * StringUtils.startsWithAny(null, null)      = false
8054      * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8055      * StringUtils.startsWithAny("abcxyz", null)     = false
8056      * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8057      * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8058      * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8059      * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8060      * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8061      * </pre>
8062      *
8063      * @param sequence the CharSequence to check, may be null
8064      * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8065      * @see StringUtils#startsWith(CharSequence, CharSequence)
8066      * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8067      *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8068      * @since 2.5
8069      * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8070      */
8071     public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8072         if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8073             return false;
8074         }
8075         for (final CharSequence searchString : searchStrings) {
8076             if (startsWith(sequence, searchString)) {
8077                 return true;
8078             }
8079         }
8080         return false;
8081     }
8082 
8083     /**
8084      * Case-insensitive check if a CharSequence starts with a specified prefix.
8085      *
8086      * <p>{@code null}s are handled without exceptions. Two {@code null}
8087      * references are considered to be equal. The comparison is case insensitive.</p>
8088      *
8089      * <pre>
8090      * StringUtils.startsWithIgnoreCase(null, null)      = true
8091      * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8092      * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8093      * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8094      * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8095      * </pre>
8096      *
8097      * @see String#startsWith(String)
8098      * @param str  the CharSequence to check, may be null
8099      * @param prefix the prefix to find, may be null
8100      * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
8101      *  both {@code null}
8102      * @since 2.4
8103      * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8104      */
8105     public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8106         return startsWith(str, prefix, true);
8107     }
8108 
8109     /**
8110      * Strips whitespace from the start and end of a String.
8111      *
8112      * <p>This is similar to {@link #trim(String)} but removes whitespace.
8113      * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8114      *
8115      * <p>A {@code null} input String returns {@code null}.</p>
8116      *
8117      * <pre>
8118      * StringUtils.strip(null)     = null
8119      * StringUtils.strip("")       = ""
8120      * StringUtils.strip("   ")    = ""
8121      * StringUtils.strip("abc")    = "abc"
8122      * StringUtils.strip("  abc")  = "abc"
8123      * StringUtils.strip("abc  ")  = "abc"
8124      * StringUtils.strip(" abc ")  = "abc"
8125      * StringUtils.strip(" ab c ") = "ab c"
8126      * </pre>
8127      *
8128      * @param str  the String to remove whitespace from, may be null
8129      * @return the stripped String, {@code null} if null String input
8130      */
8131     public static String strip(final String str) {
8132         return strip(str, null);
8133     }
8134 
8135     /**
8136      * Strips any of a set of characters from the start and end of a String.
8137      * This is similar to {@link String#trim()} but allows the characters
8138      * to be stripped to be controlled.
8139      *
8140      * <p>A {@code null} input String returns {@code null}.
8141      * An empty string ("") input returns the empty string.</p>
8142      *
8143      * <p>If the stripChars String is {@code null}, whitespace is
8144      * stripped as defined by {@link Character#isWhitespace(char)}.
8145      * Alternatively use {@link #strip(String)}.</p>
8146      *
8147      * <pre>
8148      * StringUtils.strip(null, *)          = null
8149      * StringUtils.strip("", *)            = ""
8150      * StringUtils.strip("abc", null)      = "abc"
8151      * StringUtils.strip("  abc", null)    = "abc"
8152      * StringUtils.strip("abc  ", null)    = "abc"
8153      * StringUtils.strip(" abc ", null)    = "abc"
8154      * StringUtils.strip("  abcyx", "xyz") = "  abc"
8155      * </pre>
8156      *
8157      * @param str  the String to remove characters from, may be null
8158      * @param stripChars  the characters to remove, null treated as whitespace
8159      * @return the stripped String, {@code null} if null String input
8160      */
8161     public static String strip(String str, final String stripChars) {
8162         str = stripStart(str, stripChars);
8163         return stripEnd(str, stripChars);
8164     }
8165 
8166     /**
8167      * Removes diacritics (~= accents) from a string. The case will not be altered.
8168      * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
8169      * <p>Decomposes ligatures and digraphs per the KD column in the
8170      * <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a></p>
8171      *
8172      * <pre>
8173      * StringUtils.stripAccents(null)                = null
8174      * StringUtils.stripAccents("")                  = ""
8175      * StringUtils.stripAccents("control")           = "control"
8176      * StringUtils.stripAccents("&eacute;clair")     = "eclair"
8177      * </pre>
8178      *
8179      * @param input String to be stripped
8180      * @return input text with diacritics removed
8181      *
8182      * @since 3.0
8183      */
8184     // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
8185     public static String stripAccents(final String input) {
8186         if (isEmpty(input)) {
8187             return input;
8188         }
8189         final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
8190         convertRemainingAccentCharacters(decomposed);
8191         return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
8192     }
8193 
8194     /**
8195      * Strips whitespace from the start and end of every String in an array.
8196      * Whitespace is defined by {@link Character#isWhitespace(char)}.
8197      *
8198      * <p>A new array is returned each time, except for length zero.
8199      * A {@code null} array will return {@code null}.
8200      * An empty array will return itself.
8201      * A {@code null} array entry will be ignored.</p>
8202      *
8203      * <pre>
8204      * StringUtils.stripAll(null)             = null
8205      * StringUtils.stripAll([])               = []
8206      * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
8207      * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
8208      * </pre>
8209      *
8210      * @param strs  the array to remove whitespace from, may be null
8211      * @return the stripped Strings, {@code null} if null array input
8212      */
8213     public static String[] stripAll(final String... strs) {
8214         return stripAll(strs, null);
8215     }
8216 
8217     /**
8218      * Strips any of a set of characters from the start and end of every
8219      * String in an array.
8220      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8221      *
8222      * <p>A new array is returned each time, except for length zero.
8223      * A {@code null} array will return {@code null}.
8224      * An empty array will return itself.
8225      * A {@code null} array entry will be ignored.
8226      * A {@code null} stripChars will strip whitespace as defined by
8227      * {@link Character#isWhitespace(char)}.</p>
8228      *
8229      * <pre>
8230      * StringUtils.stripAll(null, *)                = null
8231      * StringUtils.stripAll([], *)                  = []
8232      * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
8233      * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
8234      * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
8235      * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
8236      * </pre>
8237      *
8238      * @param strs  the array to remove characters from, may be null
8239      * @param stripChars  the characters to remove, null treated as whitespace
8240      * @return the stripped Strings, {@code null} if null array input
8241      */
8242     public static String[] stripAll(final String[] strs, final String stripChars) {
8243         final int strsLen = ArrayUtils.getLength(strs);
8244         if (strsLen == 0) {
8245             return strs;
8246         }
8247         final String[] newArr = new String[strsLen];
8248         Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
8249         return newArr;
8250     }
8251 
8252     /**
8253      * Strips any of a set of characters from the end of a String.
8254      *
8255      * <p>A {@code null} input String returns {@code null}.
8256      * An empty string ("") input returns the empty string.</p>
8257      *
8258      * <p>If the stripChars String is {@code null}, whitespace is
8259      * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8260      *
8261      * <pre>
8262      * StringUtils.stripEnd(null, *)          = null
8263      * StringUtils.stripEnd("", *)            = ""
8264      * StringUtils.stripEnd("abc", "")        = "abc"
8265      * StringUtils.stripEnd("abc", null)      = "abc"
8266      * StringUtils.stripEnd("  abc", null)    = "  abc"
8267      * StringUtils.stripEnd("abc  ", null)    = "abc"
8268      * StringUtils.stripEnd(" abc ", null)    = " abc"
8269      * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
8270      * StringUtils.stripEnd("120.00", ".0")   = "12"
8271      * </pre>
8272      *
8273      * @param str  the String to remove characters from, may be null
8274      * @param stripChars  the set of characters to remove, null treated as whitespace
8275      * @return the stripped String, {@code null} if null String input
8276      */
8277     public static String stripEnd(final String str, final String stripChars) {
8278         int end = length(str);
8279         if (end == 0) {
8280             return str;
8281         }
8282 
8283         if (stripChars == null) {
8284             while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8285                 end--;
8286             }
8287         } else if (stripChars.isEmpty()) {
8288             return str;
8289         } else {
8290             while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
8291                 end--;
8292             }
8293         }
8294         return str.substring(0, end);
8295     }
8296 
8297     /**
8298      * Strips any of a set of characters from the start of a String.
8299      *
8300      * <p>A {@code null} input String returns {@code null}.
8301      * An empty string ("") input returns the empty string.</p>
8302      *
8303      * <p>If the stripChars String is {@code null}, whitespace is
8304      * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8305      *
8306      * <pre>
8307      * StringUtils.stripStart(null, *)          = null
8308      * StringUtils.stripStart("", *)            = ""
8309      * StringUtils.stripStart("abc", "")        = "abc"
8310      * StringUtils.stripStart("abc", null)      = "abc"
8311      * StringUtils.stripStart("  abc", null)    = "abc"
8312      * StringUtils.stripStart("abc  ", null)    = "abc  "
8313      * StringUtils.stripStart(" abc ", null)    = "abc "
8314      * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8315      * </pre>
8316      *
8317      * @param str  the String to remove characters from, may be null
8318      * @param stripChars  the characters to remove, null treated as whitespace
8319      * @return the stripped String, {@code null} if null String input
8320      */
8321     public static String stripStart(final String str, final String stripChars) {
8322         final int strLen = length(str);
8323         if (strLen == 0) {
8324             return str;
8325         }
8326         int start = 0;
8327         if (stripChars == null) {
8328             while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8329                 start++;
8330             }
8331         } else if (stripChars.isEmpty()) {
8332             return str;
8333         } else {
8334             while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
8335                 start++;
8336             }
8337         }
8338         return str.substring(start);
8339     }
8340 
8341     /**
8342      * Strips whitespace from the start and end of a String  returning
8343      * an empty String if {@code null} input.
8344      *
8345      * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
8346      * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8347      *
8348      * <pre>
8349      * StringUtils.stripToEmpty(null)     = ""
8350      * StringUtils.stripToEmpty("")       = ""
8351      * StringUtils.stripToEmpty("   ")    = ""
8352      * StringUtils.stripToEmpty("abc")    = "abc"
8353      * StringUtils.stripToEmpty("  abc")  = "abc"
8354      * StringUtils.stripToEmpty("abc  ")  = "abc"
8355      * StringUtils.stripToEmpty(" abc ")  = "abc"
8356      * StringUtils.stripToEmpty(" ab c ") = "ab c"
8357      * </pre>
8358      *
8359      * @param str  the String to be stripped, may be null
8360      * @return the trimmed String, or an empty String if {@code null} input
8361      * @since 2.0
8362      */
8363     public static String stripToEmpty(final String str) {
8364         return str == null ? EMPTY : strip(str, null);
8365     }
8366 
8367     /**
8368      * Strips whitespace from the start and end of a String  returning
8369      * {@code null} if the String is empty ("") after the strip.
8370      *
8371      * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
8372      * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8373      *
8374      * <pre>
8375      * StringUtils.stripToNull(null)     = null
8376      * StringUtils.stripToNull("")       = null
8377      * StringUtils.stripToNull("   ")    = null
8378      * StringUtils.stripToNull("abc")    = "abc"
8379      * StringUtils.stripToNull("  abc")  = "abc"
8380      * StringUtils.stripToNull("abc  ")  = "abc"
8381      * StringUtils.stripToNull(" abc ")  = "abc"
8382      * StringUtils.stripToNull(" ab c ") = "ab c"
8383      * </pre>
8384      *
8385      * @param str  the String to be stripped, may be null
8386      * @return the stripped String,
8387      *  {@code null} if whitespace, empty or null String input
8388      * @since 2.0
8389      */
8390     public static String stripToNull(String str) {
8391         if (str == null) {
8392             return null;
8393         }
8394         str = strip(str, null);
8395         return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8396     }
8397 
8398     /**
8399      * Gets a substring from the specified String avoiding exceptions.
8400      *
8401      * <p>A negative start position can be used to start {@code n}
8402      * characters from the end of the String.</p>
8403      *
8404      * <p>A {@code null} String will return {@code null}.
8405      * An empty ("") String will return "".</p>
8406      *
8407      * <pre>
8408      * StringUtils.substring(null, *)   = null
8409      * StringUtils.substring("", *)     = ""
8410      * StringUtils.substring("abc", 0)  = "abc"
8411      * StringUtils.substring("abc", 2)  = "c"
8412      * StringUtils.substring("abc", 4)  = ""
8413      * StringUtils.substring("abc", -2) = "bc"
8414      * StringUtils.substring("abc", -4) = "abc"
8415      * </pre>
8416      *
8417      * @param str  the String to get the substring from, may be null
8418      * @param start  the position to start from, negative means
8419      *  count back from the end of the String by this many characters
8420      * @return substring from start position, {@code null} if null String input
8421      */
8422     public static String substring(final String str, int start) {
8423         if (str == null) {
8424             return null;
8425         }
8426 
8427         // handle negatives, which means last n characters
8428         if (start < 0) {
8429             start = str.length() + start; // remember start is negative
8430         }
8431 
8432         if (start < 0) {
8433             start = 0;
8434         }
8435         if (start > str.length()) {
8436             return EMPTY;
8437         }
8438 
8439         return str.substring(start);
8440     }
8441 
8442     /**
8443      * Gets a substring from the specified String avoiding exceptions.
8444      *
8445      * <p>A negative start position can be used to start/end {@code n}
8446      * characters from the end of the String.</p>
8447      *
8448      * <p>The returned substring starts with the character in the {@code start}
8449      * position and ends before the {@code end} position. All position counting is
8450      * zero-based -- i.e., to start at the beginning of the string use
8451      * {@code start = 0}. Negative start and end positions can be used to
8452      * specify offsets relative to the end of the String.</p>
8453      *
8454      * <p>If {@code start} is not strictly to the left of {@code end}, ""
8455      * is returned.</p>
8456      *
8457      * <pre>
8458      * StringUtils.substring(null, *, *)    = null
8459      * StringUtils.substring("", * ,  *)    = "";
8460      * StringUtils.substring("abc", 0, 2)   = "ab"
8461      * StringUtils.substring("abc", 2, 0)   = ""
8462      * StringUtils.substring("abc", 2, 4)   = "c"
8463      * StringUtils.substring("abc", 4, 6)   = ""
8464      * StringUtils.substring("abc", 2, 2)   = ""
8465      * StringUtils.substring("abc", -2, -1) = "b"
8466      * StringUtils.substring("abc", -4, 2)  = "ab"
8467      * </pre>
8468      *
8469      * @param str  the String to get the substring from, may be null
8470      * @param start  the position to start from, negative means
8471      *  count back from the end of the String by this many characters
8472      * @param end  the position to end at (exclusive), negative means
8473      *  count back from the end of the String by this many characters
8474      * @return substring from start position to end position,
8475      *  {@code null} if null String input
8476      */
8477     public static String substring(final String str, int start, int end) {
8478         if (str == null) {
8479             return null;
8480         }
8481 
8482         // handle negatives
8483         if (end < 0) {
8484             end = str.length() + end; // remember end is negative
8485         }
8486         if (start < 0) {
8487             start = str.length() + start; // remember start is negative
8488         }
8489 
8490         // check length next
8491         if (end > str.length()) {
8492             end = str.length();
8493         }
8494 
8495         // if start is greater than end, return ""
8496         if (start > end) {
8497             return EMPTY;
8498         }
8499 
8500         if (start < 0) {
8501             start = 0;
8502         }
8503         if (end < 0) {
8504             end = 0;
8505         }
8506 
8507         return str.substring(start, end);
8508     }
8509 
8510     /**
8511      * Gets the substring after the first occurrence of a separator.
8512      * The separator is not returned.
8513      *
8514      * <p>A {@code null} string input will return {@code null}.
8515      * An empty ("") string input will return the empty string.
8516      *
8517      * <p>If nothing is found, the empty string is returned.</p>
8518      *
8519      * <pre>
8520      * StringUtils.substringAfter(null, *)      = null
8521      * StringUtils.substringAfter("", *)        = ""
8522      * StringUtils.substringAfter("abc", 'a')   = "bc"
8523      * StringUtils.substringAfter("abcba", 'b') = "cba"
8524      * StringUtils.substringAfter("abc", 'c')   = ""
8525      * StringUtils.substringAfter("abc", 'd')   = ""
8526      * StringUtils.substringAfter(" abc", 32)   = "abc"
8527      * </pre>
8528      *
8529      * @param str  the String to get a substring from, may be null
8530      * @param separator  the character (Unicode code point) to search.
8531      * @return the substring after the first occurrence of the separator,
8532      *  {@code null} if null String input
8533      * @since 3.11
8534      */
8535     public static String substringAfter(final String str, final int separator) {
8536         if (isEmpty(str)) {
8537             return str;
8538         }
8539         final int pos = str.indexOf(separator);
8540         if (pos == INDEX_NOT_FOUND) {
8541             return EMPTY;
8542         }
8543         return str.substring(pos + 1);
8544     }
8545 
8546     /**
8547      * Gets the substring after the first occurrence of a separator.
8548      * The separator is not returned.
8549      *
8550      * <p>A {@code null} string input will return {@code null}.
8551      * An empty ("") string input will return the empty string.
8552      * A {@code null} separator will return the empty string if the
8553      * input string is not {@code null}.</p>
8554      *
8555      * <p>If nothing is found, the empty string is returned.</p>
8556      *
8557      * <pre>
8558      * StringUtils.substringAfter(null, *)      = null
8559      * StringUtils.substringAfter("", *)        = ""
8560      * StringUtils.substringAfter(*, null)      = ""
8561      * StringUtils.substringAfter("abc", "a")   = "bc"
8562      * StringUtils.substringAfter("abcba", "b") = "cba"
8563      * StringUtils.substringAfter("abc", "c")   = ""
8564      * StringUtils.substringAfter("abc", "d")   = ""
8565      * StringUtils.substringAfter("abc", "")    = "abc"
8566      * </pre>
8567      *
8568      * @param str  the String to get a substring from, may be null
8569      * @param separator  the String to search for, may be null
8570      * @return the substring after the first occurrence of the separator,
8571      *  {@code null} if null String input
8572      * @since 2.0
8573      */
8574     public static String substringAfter(final String str, final String separator) {
8575         if (isEmpty(str)) {
8576             return str;
8577         }
8578         if (separator == null) {
8579             return EMPTY;
8580         }
8581         final int pos = str.indexOf(separator);
8582         if (pos == INDEX_NOT_FOUND) {
8583             return EMPTY;
8584         }
8585         return str.substring(pos + separator.length());
8586     }
8587 
8588     /**
8589      * Gets the substring after the last occurrence of a separator.
8590      * The separator is not returned.
8591      *
8592      * <p>A {@code null} string input will return {@code null}.
8593      * An empty ("") string input will return the empty string.
8594      *
8595      * <p>If nothing is found, the empty string is returned.</p>
8596      *
8597      * <pre>
8598      * StringUtils.substringAfterLast(null, *)      = null
8599      * StringUtils.substringAfterLast("", *)        = ""
8600      * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8601      * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8602      * StringUtils.substringAfterLast("abcba", 'b') = "a"
8603      * StringUtils.substringAfterLast("abc", 'c')   = ""
8604      * StringUtils.substringAfterLast("a", 'a')     = ""
8605      * StringUtils.substringAfterLast("a", 'z')     = ""
8606      * </pre>
8607      *
8608      * @param str  the String to get a substring from, may be null
8609      * @param separator  the character (Unicode code point) to search.
8610      * @return the substring after the last occurrence of the separator,
8611      *  {@code null} if null String input
8612      * @since 3.11
8613      */
8614     public static String substringAfterLast(final String str, final int separator) {
8615         if (isEmpty(str)) {
8616             return str;
8617         }
8618         final int pos = str.lastIndexOf(separator);
8619         if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8620             return EMPTY;
8621         }
8622         return str.substring(pos + 1);
8623     }
8624 
8625     /**
8626      * Gets the substring after the last occurrence of a separator.
8627      * The separator is not returned.
8628      *
8629      * <p>A {@code null} string input will return {@code null}.
8630      * An empty ("") string input will return the empty string.
8631      * An empty or {@code null} separator will return the empty string if
8632      * the input string is not {@code null}.</p>
8633      *
8634      * <p>If nothing is found, the empty string is returned.</p>
8635      *
8636      * <pre>
8637      * StringUtils.substringAfterLast(null, *)      = null
8638      * StringUtils.substringAfterLast("", *)        = ""
8639      * StringUtils.substringAfterLast(*, "")        = ""
8640      * StringUtils.substringAfterLast(*, null)      = ""
8641      * StringUtils.substringAfterLast("abc", "a")   = "bc"
8642      * StringUtils.substringAfterLast("abcba", "b") = "a"
8643      * StringUtils.substringAfterLast("abc", "c")   = ""
8644      * StringUtils.substringAfterLast("a", "a")     = ""
8645      * StringUtils.substringAfterLast("a", "z")     = ""
8646      * </pre>
8647      *
8648      * @param str  the String to get a substring from, may be null
8649      * @param separator  the String to search for, may be null
8650      * @return the substring after the last occurrence of the separator,
8651      *  {@code null} if null String input
8652      * @since 2.0
8653      */
8654     public static String substringAfterLast(final String str, final String separator) {
8655         if (isEmpty(str)) {
8656             return str;
8657         }
8658         if (isEmpty(separator)) {
8659             return EMPTY;
8660         }
8661         final int pos = str.lastIndexOf(separator);
8662         if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
8663             return EMPTY;
8664         }
8665         return str.substring(pos + separator.length());
8666     }
8667 
8668     /**
8669      * Gets the substring before the first occurrence of a separator. The separator is not returned.
8670      *
8671      * <p>
8672      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8673      * </p>
8674      *
8675      * <p>
8676      * If nothing is found, the string input is returned.
8677      * </p>
8678      *
8679      * <pre>
8680      * StringUtils.substringBefore(null, *)      = null
8681      * StringUtils.substringBefore("", *)        = ""
8682      * StringUtils.substringBefore("abc", 'a')   = ""
8683      * StringUtils.substringBefore("abcba", 'b') = "a"
8684      * StringUtils.substringBefore("abc", 'c')   = "ab"
8685      * StringUtils.substringBefore("abc", 'd')   = "abc"
8686      * </pre>
8687      *
8688      * @param str the String to get a substring from, may be null
8689      * @param separator the character (Unicode code point) to search.
8690      * @return the substring before the first occurrence of the separator, {@code null} if null String input
8691      * @since 3.12.0
8692      */
8693     public static String substringBefore(final String str, final int separator) {
8694         if (isEmpty(str)) {
8695             return str;
8696         }
8697         final int pos = str.indexOf(separator);
8698         if (pos == INDEX_NOT_FOUND) {
8699             return str;
8700         }
8701         return str.substring(0, pos);
8702     }
8703 
8704     /**
8705      * Gets the substring before the first occurrence of a separator.
8706      * The separator is not returned.
8707      *
8708      * <p>A {@code null} string input will return {@code null}.
8709      * An empty ("") string input will return the empty string.
8710      * A {@code null} separator will return the input string.</p>
8711      *
8712      * <p>If nothing is found, the string input is returned.</p>
8713      *
8714      * <pre>
8715      * StringUtils.substringBefore(null, *)      = null
8716      * StringUtils.substringBefore("", *)        = ""
8717      * StringUtils.substringBefore("abc", "a")   = ""
8718      * StringUtils.substringBefore("abcba", "b") = "a"
8719      * StringUtils.substringBefore("abc", "c")   = "ab"
8720      * StringUtils.substringBefore("abc", "d")   = "abc"
8721      * StringUtils.substringBefore("abc", "")    = ""
8722      * StringUtils.substringBefore("abc", null)  = "abc"
8723      * </pre>
8724      *
8725      * @param str  the String to get a substring from, may be null
8726      * @param separator  the String to search for, may be null
8727      * @return the substring before the first occurrence of the separator,
8728      *  {@code null} if null String input
8729      * @since 2.0
8730      */
8731     public static String substringBefore(final String str, final String separator) {
8732         if (isEmpty(str) || separator == null) {
8733             return str;
8734         }
8735         if (separator.isEmpty()) {
8736             return EMPTY;
8737         }
8738         final int pos = str.indexOf(separator);
8739         if (pos == INDEX_NOT_FOUND) {
8740             return str;
8741         }
8742         return str.substring(0, pos);
8743     }
8744 
8745     /**
8746      * Gets the substring before the last occurrence of a separator.
8747      * The separator is not returned.
8748      *
8749      * <p>A {@code null} string input will return {@code null}.
8750      * An empty ("") string input will return the empty string.
8751      * An empty or {@code null} separator will return the input string.</p>
8752      *
8753      * <p>If nothing is found, the string input is returned.</p>
8754      *
8755      * <pre>
8756      * StringUtils.substringBeforeLast(null, *)      = null
8757      * StringUtils.substringBeforeLast("", *)        = ""
8758      * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8759      * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8760      * StringUtils.substringBeforeLast("a", "a")     = ""
8761      * StringUtils.substringBeforeLast("a", "z")     = "a"
8762      * StringUtils.substringBeforeLast("a", null)    = "a"
8763      * StringUtils.substringBeforeLast("a", "")      = "a"
8764      * </pre>
8765      *
8766      * @param str  the String to get a substring from, may be null
8767      * @param separator  the String to search for, may be null
8768      * @return the substring before the last occurrence of the separator,
8769      *  {@code null} if null String input
8770      * @since 2.0
8771      */
8772     public static String substringBeforeLast(final String str, final String separator) {
8773         if (isEmpty(str) || isEmpty(separator)) {
8774             return str;
8775         }
8776         final int pos = str.lastIndexOf(separator);
8777         if (pos == INDEX_NOT_FOUND) {
8778             return str;
8779         }
8780         return str.substring(0, pos);
8781     }
8782 
8783     /**
8784      * Gets the String that is nested in between two instances of the
8785      * same String.
8786      *
8787      * <p>A {@code null} input String returns {@code null}.
8788      * A {@code null} tag returns {@code null}.</p>
8789      *
8790      * <pre>
8791      * StringUtils.substringBetween(null, *)            = null
8792      * StringUtils.substringBetween("", "")             = ""
8793      * StringUtils.substringBetween("", "tag")          = null
8794      * StringUtils.substringBetween("tagabctag", null)  = null
8795      * StringUtils.substringBetween("tagabctag", "")    = ""
8796      * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8797      * </pre>
8798      *
8799      * @param str  the String containing the substring, may be null
8800      * @param tag  the String before and after the substring, may be null
8801      * @return the substring, {@code null} if no match
8802      * @since 2.0
8803      */
8804     public static String substringBetween(final String str, final String tag) {
8805         return substringBetween(str, tag, tag);
8806     }
8807 
8808     /**
8809      * Gets the String that is nested in between two Strings.
8810      * Only the first match is returned.
8811      *
8812      * <p>A {@code null} input String returns {@code null}.
8813      * A {@code null} open/close returns {@code null} (no match).
8814      * An empty ("") open and close returns an empty string.</p>
8815      *
8816      * <pre>
8817      * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8818      * StringUtils.substringBetween(null, *, *)          = null
8819      * StringUtils.substringBetween(*, null, *)          = null
8820      * StringUtils.substringBetween(*, *, null)          = null
8821      * StringUtils.substringBetween("", "", "")          = ""
8822      * StringUtils.substringBetween("", "", "]")         = null
8823      * StringUtils.substringBetween("", "[", "]")        = null
8824      * StringUtils.substringBetween("yabcz", "", "")     = ""
8825      * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8826      * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8827      * </pre>
8828      *
8829      * @param str  the String containing the substring, may be null
8830      * @param open  the String before the substring, may be null
8831      * @param close  the String after the substring, may be null
8832      * @return the substring, {@code null} if no match
8833      * @since 2.0
8834      */
8835     public static String substringBetween(final String str, final String open, final String close) {
8836         if (!ObjectUtils.allNotNull(str, open, close)) {
8837             return null;
8838         }
8839         final int start = str.indexOf(open);
8840         if (start != INDEX_NOT_FOUND) {
8841             final int end = str.indexOf(close, start + open.length());
8842             if (end != INDEX_NOT_FOUND) {
8843                 return str.substring(start + open.length(), end);
8844             }
8845         }
8846         return null;
8847     }
8848 
8849     /**
8850      * Searches a String for substrings delimited by a start and end tag,
8851      * returning all matching substrings in an array.
8852      *
8853      * <p>A {@code null} input String returns {@code null}.
8854      * A {@code null} open/close returns {@code null} (no match).
8855      * An empty ("") open/close returns {@code null} (no match).</p>
8856      *
8857      * <pre>
8858      * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8859      * StringUtils.substringsBetween(null, *, *)            = null
8860      * StringUtils.substringsBetween(*, null, *)            = null
8861      * StringUtils.substringsBetween(*, *, null)            = null
8862      * StringUtils.substringsBetween("", "[", "]")          = []
8863      * </pre>
8864      *
8865      * @param str  the String containing the substrings, null returns null, empty returns empty
8866      * @param open  the String identifying the start of the substring, empty returns null
8867      * @param close  the String identifying the end of the substring, empty returns null
8868      * @return a String Array of substrings, or {@code null} if no match
8869      * @since 2.3
8870      */
8871     public static String[] substringsBetween(final String str, final String open, final String close) {
8872         if (str == null || isEmpty(open) || isEmpty(close)) {
8873             return null;
8874         }
8875         final int strLen = str.length();
8876         if (strLen == 0) {
8877             return ArrayUtils.EMPTY_STRING_ARRAY;
8878         }
8879         final int closeLen = close.length();
8880         final int openLen = open.length();
8881         final List<String> list = new ArrayList<>();
8882         int pos = 0;
8883         while (pos < strLen - closeLen) {
8884             int start = str.indexOf(open, pos);
8885             if (start < 0) {
8886                 break;
8887             }
8888             start += openLen;
8889             final int end = str.indexOf(close, start);
8890             if (end < 0) {
8891                 break;
8892             }
8893             list.add(str.substring(start, end));
8894             pos = end + closeLen;
8895         }
8896         if (list.isEmpty()) {
8897             return null;
8898         }
8899         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8900     }
8901 
8902     /**
8903      * Swaps the case of a String changing upper and title case to
8904      * lower case, and lower case to upper case.
8905      *
8906      * <ul>
8907      *  <li>Upper case character converts to Lower case</li>
8908      *  <li>Title case character converts to Lower case</li>
8909      *  <li>Lower case character converts to Upper case</li>
8910      * </ul>
8911      *
8912      * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
8913      * A {@code null} input String returns {@code null}.</p>
8914      *
8915      * <pre>
8916      * StringUtils.swapCase(null)                 = null
8917      * StringUtils.swapCase("")                   = ""
8918      * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8919      * </pre>
8920      *
8921      * <p>NOTE: This method changed in Lang version 2.0.
8922      * It no longer performs a word based algorithm.
8923      * If you only use ASCII, you will notice no change.
8924      * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
8925      *
8926      * @param str  the String to swap case, may be null
8927      * @return the changed String, {@code null} if null String input
8928      */
8929     public static String swapCase(final String str) {
8930         if (isEmpty(str)) {
8931             return str;
8932         }
8933 
8934         final int strLen = str.length();
8935         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8936         int outOffset = 0;
8937         for (int i = 0; i < strLen; ) {
8938             final int oldCodepoint = str.codePointAt(i);
8939             final int newCodePoint;
8940             if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8941                 newCodePoint = Character.toLowerCase(oldCodepoint);
8942             } else if (Character.isLowerCase(oldCodepoint)) {
8943                 newCodePoint = Character.toUpperCase(oldCodepoint);
8944             } else {
8945                 newCodePoint = oldCodepoint;
8946             }
8947             newCodePoints[outOffset++] = newCodePoint;
8948             i += Character.charCount(newCodePoint);
8949          }
8950         return new String(newCodePoints, 0, outOffset);
8951     }
8952 
8953     /**
8954      * Converts a {@link CharSequence} into an array of code points.
8955      *
8956      * <p>Valid pairs of surrogate code units will be converted into a single supplementary
8957      * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
8958      * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
8959      *
8960      * <pre>
8961      * StringUtils.toCodePoints(null)   =  null
8962      * StringUtils.toCodePoints("")     =  []  // empty array
8963      * </pre>
8964      *
8965      * @param cs the character sequence to convert
8966      * @return an array of code points
8967      * @since 3.6
8968      */
8969     public static int[] toCodePoints(final CharSequence cs) {
8970         if (cs == null) {
8971             return null;
8972         }
8973         if (cs.length() == 0) {
8974             return ArrayUtils.EMPTY_INT_ARRAY;
8975         }
8976 
8977         final String s = cs.toString();
8978         final int[] result = new int[s.codePointCount(0, s.length())];
8979         int index = 0;
8980         for (int i = 0; i < result.length; i++) {
8981             result[i] = s.codePointAt(index);
8982             index += Character.charCount(result[i]);
8983         }
8984         return result;
8985     }
8986 
8987     /**
8988      * Converts a {@code byte[]} to a String using the specified character encoding.
8989      *
8990      * @param bytes
8991      *            the byte array to read from
8992      * @param charset
8993      *            the encoding to use, if null then use the platform default
8994      * @return a new String
8995      * @throws NullPointerException
8996      *             if {@code bytes} is null
8997      * @since 3.2
8998      * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8999      */
9000     public static String toEncodedString(final byte[] bytes, final Charset charset) {
9001         return new String(bytes, Charsets.toCharset(charset));
9002     }
9003 
9004     /**
9005      * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
9006      *
9007      * @param source A source String or null.
9008      * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
9009      * @since 3.10
9010      */
9011     public static String toRootLowerCase(final String source) {
9012         return source == null ? null : source.toLowerCase(Locale.ROOT);
9013     }
9014 
9015     /**
9016      * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
9017      *
9018      * @param source A source String or null.
9019      * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
9020      * @since 3.10
9021      */
9022     public static String toRootUpperCase(final String source) {
9023         return source == null ? null : source.toUpperCase(Locale.ROOT);
9024     }
9025 
9026     /**
9027      * Converts a {@code byte[]} to a String using the specified character encoding.
9028      *
9029      * @param bytes
9030      *            the byte array to read from
9031      * @param charsetName
9032      *            the encoding to use, if null then use the platform default
9033      * @return a new String
9034      * @throws NullPointerException
9035      *             if the input is null
9036      * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
9037      * @since 3.1
9038      */
9039     @Deprecated
9040     public static String toString(final byte[] bytes, final String charsetName) {
9041         return new String(bytes, Charsets.toCharset(charsetName));
9042     }
9043 
9044     private static String toStringOrEmpty(final Object obj) {
9045         return Objects.toString(obj, EMPTY);
9046     }
9047 
9048     /**
9049      * Removes control characters (char &lt;= 32) from both
9050      * ends of this String, handling {@code null} by returning
9051      * {@code null}.
9052      *
9053      * <p>The String is trimmed using {@link String#trim()}.
9054      * Trim removes start and end characters &lt;= 32.
9055      * To strip whitespace use {@link #strip(String)}.</p>
9056      *
9057      * <p>To trim your choice of characters, use the
9058      * {@link #strip(String, String)} methods.</p>
9059      *
9060      * <pre>
9061      * StringUtils.trim(null)          = null
9062      * StringUtils.trim("")            = ""
9063      * StringUtils.trim("     ")       = ""
9064      * StringUtils.trim("abc")         = "abc"
9065      * StringUtils.trim("    abc    ") = "abc"
9066      * </pre>
9067      *
9068      * @param str  the String to be trimmed, may be null
9069      * @return the trimmed string, {@code null} if null String input
9070      */
9071     public static String trim(final String str) {
9072         return str == null ? null : str.trim();
9073     }
9074 
9075     /**
9076      * Removes control characters (char &lt;= 32) from both
9077      * ends of this String returning an empty String ("") if the String
9078      * is empty ("") after the trim or if it is {@code null}.
9079      *
9080      * <p>The String is trimmed using {@link String#trim()}.
9081      * Trim removes start and end characters &lt;= 32.
9082      * To strip whitespace use {@link #stripToEmpty(String)}.
9083      *
9084      * <pre>
9085      * StringUtils.trimToEmpty(null)          = ""
9086      * StringUtils.trimToEmpty("")            = ""
9087      * StringUtils.trimToEmpty("     ")       = ""
9088      * StringUtils.trimToEmpty("abc")         = "abc"
9089      * StringUtils.trimToEmpty("    abc    ") = "abc"
9090      * </pre>
9091      *
9092      * @param str  the String to be trimmed, may be null
9093      * @return the trimmed String, or an empty String if {@code null} input
9094      * @since 2.0
9095      */
9096     public static String trimToEmpty(final String str) {
9097         return str == null ? EMPTY : str.trim();
9098     }
9099 
9100     /**
9101      * Removes control characters (char &lt;= 32) from both
9102      * ends of this String returning {@code null} if the String is
9103      * empty ("") after the trim or if it is {@code null}.
9104      *
9105      * <p>The String is trimmed using {@link String#trim()}.
9106      * Trim removes start and end characters &lt;= 32.
9107      * To strip whitespace use {@link #stripToNull(String)}.
9108      *
9109      * <pre>
9110      * StringUtils.trimToNull(null)          = null
9111      * StringUtils.trimToNull("")            = null
9112      * StringUtils.trimToNull("     ")       = null
9113      * StringUtils.trimToNull("abc")         = "abc"
9114      * StringUtils.trimToNull("    abc    ") = "abc"
9115      * </pre>
9116      *
9117      * @param str  the String to be trimmed, may be null
9118      * @return the trimmed String,
9119      *  {@code null} if only chars &lt;= 32, empty or null String input
9120      * @since 2.0
9121      */
9122     public static String trimToNull(final String str) {
9123         final String ts = trim(str);
9124         return isEmpty(ts) ? null : ts;
9125     }
9126 
9127     /**
9128      * Truncates a String. This will turn
9129      * "Now is the time for all good men" into "Now is the time for".
9130      *
9131      * <p>Specifically:</p>
9132      * <ul>
9133      *   <li>If {@code str} is less than {@code maxWidth} characters
9134      *       long, return it.</li>
9135      *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
9136      *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9137      *       {@link IllegalArgumentException}.</li>
9138      *   <li>In no case will it return a String of length greater than
9139      *       {@code maxWidth}.</li>
9140      * </ul>
9141      *
9142      * <pre>
9143      * StringUtils.truncate(null, 0)       = null
9144      * StringUtils.truncate(null, 2)       = null
9145      * StringUtils.truncate("", 4)         = ""
9146      * StringUtils.truncate("abcdefg", 4)  = "abcd"
9147      * StringUtils.truncate("abcdefg", 6)  = "abcdef"
9148      * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
9149      * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
9150      * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
9151      * </pre>
9152      *
9153      * @param str  the String to truncate, may be null
9154      * @param maxWidth  maximum length of result String, must be positive
9155      * @return truncated String, {@code null} if null String input
9156      * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
9157      * @since 3.5
9158      */
9159     public static String truncate(final String str, final int maxWidth) {
9160         return truncate(str, 0, maxWidth);
9161     }
9162 
9163     /**
9164      * Truncates a String. This will turn
9165      * "Now is the time for all good men" into "is the time for all".
9166      *
9167      * <p>Works like {@code truncate(String, int)}, but allows you to specify
9168      * a "left edge" offset.
9169      *
9170      * <p>Specifically:</p>
9171      * <ul>
9172      *   <li>If {@code str} is less than {@code maxWidth} characters
9173      *       long, return it.</li>
9174      *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
9175      *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9176      *       {@link IllegalArgumentException}.</li>
9177      *   <li>If {@code offset} is less than {@code 0}, throw an
9178      *       {@link IllegalArgumentException}.</li>
9179      *   <li>In no case will it return a String of length greater than
9180      *       {@code maxWidth}.</li>
9181      * </ul>
9182      *
9183      * <pre>
9184      * StringUtils.truncate(null, 0, 0) = null
9185      * StringUtils.truncate(null, 2, 4) = null
9186      * StringUtils.truncate("", 0, 10) = ""
9187      * StringUtils.truncate("", 2, 10) = ""
9188      * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
9189      * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
9190      * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
9191      * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
9192      * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
9193      * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
9194      * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
9195      * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
9196      * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
9197      * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
9198      * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
9199      * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
9200      * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
9201      * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
9202      * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
9203      * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
9204      * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
9205      * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
9206      * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
9207      * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
9208      * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
9209      * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
9210      * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
9211      * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
9212      * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
9213      * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
9214      * </pre>
9215      *
9216      * @param str  the String to truncate, may be null
9217      * @param offset  left edge of source String
9218      * @param maxWidth  maximum length of result String, must be positive
9219      * @return truncated String, {@code null} if null String input
9220      * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
9221      * @since 3.5
9222      */
9223     public static String truncate(final String str, final int offset, final int maxWidth) {
9224         if (offset < 0) {
9225             throw new IllegalArgumentException("offset cannot be negative");
9226         }
9227         if (maxWidth < 0) {
9228             throw new IllegalArgumentException("maxWith cannot be negative");
9229         }
9230         if (str == null) {
9231             return null;
9232         }
9233         if (offset > str.length()) {
9234             return EMPTY;
9235         }
9236         if (str.length() > maxWidth) {
9237             final int ix = Math.min(offset + maxWidth, str.length());
9238             return str.substring(offset, ix);
9239         }
9240         return str.substring(offset);
9241     }
9242 
9243     /**
9244      * Uncapitalizes a String, changing the first character to lower case as
9245      * per {@link Character#toLowerCase(int)}. No other characters are changed.
9246      *
9247      * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
9248      * A {@code null} input String returns {@code null}.</p>
9249      *
9250      * <pre>
9251      * StringUtils.uncapitalize(null)  = null
9252      * StringUtils.uncapitalize("")    = ""
9253      * StringUtils.uncapitalize("cat") = "cat"
9254      * StringUtils.uncapitalize("Cat") = "cat"
9255      * StringUtils.uncapitalize("CAT") = "cAT"
9256      * </pre>
9257      *
9258      * @param str the String to uncapitalize, may be null
9259      * @return the uncapitalized String, {@code null} if null String input
9260      * @see org.apache.commons.text.WordUtils#uncapitalize(String)
9261      * @see #capitalize(String)
9262      * @since 2.0
9263      */
9264     public static String uncapitalize(final String str) {
9265         final int strLen = length(str);
9266         if (strLen == 0) {
9267             return str;
9268         }
9269 
9270         final int firstCodePoint = str.codePointAt(0);
9271         final int newCodePoint = Character.toLowerCase(firstCodePoint);
9272         if (firstCodePoint == newCodePoint) {
9273             // already capitalized
9274             return str;
9275         }
9276 
9277         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
9278         int outOffset = 0;
9279         newCodePoints[outOffset++] = newCodePoint; // copy the first code point
9280         for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) {
9281             final int codePoint = str.codePointAt(inOffset);
9282             newCodePoints[outOffset++] = codePoint; // copy the remaining ones
9283             inOffset += Character.charCount(codePoint);
9284          }
9285         return new String(newCodePoints, 0, outOffset);
9286     }
9287 
9288     /**
9289      * Unwraps a given string from a character.
9290      *
9291      * <pre>
9292      * StringUtils.unwrap(null, null)         = null
9293      * StringUtils.unwrap(null, '\0')         = null
9294      * StringUtils.unwrap(null, '1')          = null
9295      * StringUtils.unwrap("a", 'a')           = "a"
9296      * StringUtils.unwrap("aa", 'a')           = ""
9297      * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9298      * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
9299      * StringUtils.unwrap("A", '#')           = "A"
9300      * StringUtils.unwrap("#A", '#')          = "#A"
9301      * StringUtils.unwrap("A#", '#')          = "A#"
9302      * </pre>
9303      *
9304      * @param str
9305      *          the String to be unwrapped, can be null
9306      * @param wrapChar
9307      *          the character used to unwrap
9308      * @return unwrapped String or the original string
9309      *          if it is not quoted properly with the wrapChar
9310      * @since 3.6
9311      */
9312     public static String unwrap(final String str, final char wrapChar) {
9313         if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9314             return str;
9315         }
9316 
9317         if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9318             final int startIndex = 0;
9319             final int endIndex = str.length() - 1;
9320 
9321             return str.substring(startIndex + 1, endIndex);
9322         }
9323 
9324         return str;
9325     }
9326 
9327     /**
9328      * Unwraps a given string from another string.
9329      *
9330      * <pre>
9331      * StringUtils.unwrap(null, null)         = null
9332      * StringUtils.unwrap(null, "")           = null
9333      * StringUtils.unwrap(null, "1")          = null
9334      * StringUtils.unwrap("a", "a")           = "a"
9335      * StringUtils.unwrap("aa", "a")          = ""
9336      * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9337      * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9338      * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9339      * StringUtils.unwrap("A", "#")           = "A"
9340      * StringUtils.unwrap("#A", "#")          = "#A"
9341      * StringUtils.unwrap("A#", "#")          = "A#"
9342      * </pre>
9343      *
9344      * @param str
9345      *          the String to be unwrapped, can be null
9346      * @param wrapToken
9347      *          the String used to unwrap
9348      * @return unwrapped String or the original string
9349      *          if it is not quoted properly with the wrapToken
9350      * @since 3.6
9351      */
9352     public static String unwrap(final String str, final String wrapToken) {
9353         if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
9354             return str;
9355         }
9356 
9357         if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9358             return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
9359         }
9360 
9361         return str;
9362     }
9363 
9364     /**
9365      * Converts a String to upper case as per {@link String#toUpperCase()}.
9366      *
9367      * <p>A {@code null} input String returns {@code null}.</p>
9368      *
9369      * <pre>
9370      * StringUtils.upperCase(null)  = null
9371      * StringUtils.upperCase("")    = ""
9372      * StringUtils.upperCase("aBc") = "ABC"
9373      * </pre>
9374      *
9375      * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
9376      * the result of this method is affected by the current locale.
9377      * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
9378      * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
9379      *
9380      * @param str  the String to upper case, may be null
9381      * @return the upper-cased String, {@code null} if null String input
9382      */
9383     public static String upperCase(final String str) {
9384         if (str == null) {
9385             return null;
9386         }
9387         return str.toUpperCase();
9388     }
9389 
9390     /**
9391      * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9392      *
9393      * <p>A {@code null} input String returns {@code null}.</p>
9394      *
9395      * <pre>
9396      * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9397      * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9398      * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9399      * </pre>
9400      *
9401      * @param str  the String to upper case, may be null
9402      * @param locale  the locale that defines the case transformation rules, must not be null
9403      * @return the upper-cased String, {@code null} if null String input
9404      * @since 2.5
9405      */
9406     public static String upperCase(final String str, final Locale locale) {
9407         if (str == null) {
9408             return null;
9409         }
9410         return str.toUpperCase(LocaleUtils.toLocale(locale));
9411     }
9412 
9413     /**
9414      * Returns the string representation of the {@code char} array or null.
9415      *
9416      * @param value the character array.
9417      * @return a String or null
9418      * @see String#valueOf(char[])
9419      * @since 3.9
9420      */
9421     public static String valueOf(final char[] value) {
9422         return value == null ? null : String.valueOf(value);
9423     }
9424 
9425     /**
9426      * Wraps a string with a char.
9427      *
9428      * <pre>
9429      * StringUtils.wrap(null, *)        = null
9430      * StringUtils.wrap("", *)          = ""
9431      * StringUtils.wrap("ab", '\0')     = "ab"
9432      * StringUtils.wrap("ab", 'x')      = "xabx"
9433      * StringUtils.wrap("ab", '\'')     = "'ab'"
9434      * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9435      * </pre>
9436      *
9437      * @param str
9438      *            the string to be wrapped, may be {@code null}
9439      * @param wrapWith
9440      *            the char that will wrap {@code str}
9441      * @return the wrapped string, or {@code null} if {@code str == null}
9442      * @since 3.4
9443      */
9444     public static String wrap(final String str, final char wrapWith) {
9445 
9446         if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9447             return str;
9448         }
9449 
9450         return wrapWith + str + wrapWith;
9451     }
9452 
9453     /**
9454      * Wraps a String with another String.
9455      *
9456      * <p>
9457      * A {@code null} input String returns {@code null}.
9458      * </p>
9459      *
9460      * <pre>
9461      * StringUtils.wrap(null, *)         = null
9462      * StringUtils.wrap("", *)           = ""
9463      * StringUtils.wrap("ab", null)      = "ab"
9464      * StringUtils.wrap("ab", "x")       = "xabx"
9465      * StringUtils.wrap("ab", "\"")      = "\"ab\""
9466      * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9467      * StringUtils.wrap("ab", "'")       = "'ab'"
9468      * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9469      * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9470      * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9471      * </pre>
9472      *
9473      * @param str
9474      *            the String to be wrapper, may be null
9475      * @param wrapWith
9476      *            the String that will wrap str
9477      * @return wrapped String, {@code null} if null String input
9478      * @since 3.4
9479      */
9480     public static String wrap(final String str, final String wrapWith) {
9481 
9482         if (isEmpty(str) || isEmpty(wrapWith)) {
9483             return str;
9484         }
9485 
9486         return wrapWith.concat(str).concat(wrapWith);
9487     }
9488 
9489     /**
9490      * Wraps a string with a char if that char is missing from the start or end of the given string.
9491      *
9492      * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9493      *
9494      * <pre>
9495      * StringUtils.wrapIfMissing(null, *)        = null
9496      * StringUtils.wrapIfMissing("", *)          = ""
9497      * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9498      * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9499      * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9500      * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9501      * StringUtils.wrapIfMissing("/", '/')  = "/"
9502      * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9503      * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9504      * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9505      * </pre>
9506      *
9507      * @param str
9508      *            the string to be wrapped, may be {@code null}
9509      * @param wrapWith
9510      *            the char that will wrap {@code str}
9511      * @return the wrapped string, or {@code null} if {@code str == null}
9512      * @since 3.5
9513      */
9514     public static String wrapIfMissing(final String str, final char wrapWith) {
9515         if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9516             return str;
9517         }
9518         final boolean wrapStart = str.charAt(0) != wrapWith;
9519         final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9520         if (!wrapStart && !wrapEnd) {
9521             return str;
9522         }
9523 
9524         final StringBuilder builder = new StringBuilder(str.length() + 2);
9525         if (wrapStart) {
9526             builder.append(wrapWith);
9527         }
9528         builder.append(str);
9529         if (wrapEnd) {
9530             builder.append(wrapWith);
9531         }
9532         return builder.toString();
9533     }
9534 
9535     /**
9536      * Wraps a string with a string if that string is missing from the start or end of the given string.
9537      *
9538      * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9539      *
9540      * <pre>
9541      * StringUtils.wrapIfMissing(null, *)         = null
9542      * StringUtils.wrapIfMissing("", *)           = ""
9543      * StringUtils.wrapIfMissing("ab", null)      = "ab"
9544      * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9545      * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9546      * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9547      * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9548      * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9549      * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9550      * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9551      * StringUtils.wrapIfMissing("/", "/")  = "/"
9552      * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9553      * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9554      * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9555      * </pre>
9556      *
9557      * @param str
9558      *            the string to be wrapped, may be {@code null}
9559      * @param wrapWith
9560      *            the string that will wrap {@code str}
9561      * @return the wrapped string, or {@code null} if {@code str == null}
9562      * @since 3.5
9563      */
9564     public static String wrapIfMissing(final String str, final String wrapWith) {
9565         if (isEmpty(str) || isEmpty(wrapWith)) {
9566             return str;
9567         }
9568 
9569         final boolean wrapStart = !str.startsWith(wrapWith);
9570         final boolean wrapEnd = !str.endsWith(wrapWith);
9571         if (!wrapStart && !wrapEnd) {
9572             return str;
9573         }
9574 
9575         final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9576         if (wrapStart) {
9577             builder.append(wrapWith);
9578         }
9579         builder.append(str);
9580         if (wrapEnd) {
9581             builder.append(wrapWith);
9582         }
9583         return builder.toString();
9584     }
9585 
9586     /**
9587      * {@link StringUtils} instances should NOT be constructed in
9588      * standard programming. Instead, the class should be used as
9589      * {@code StringUtils.trim(" foo ");}.
9590      *
9591      * <p>This constructor is public to permit tools that require a JavaBean
9592      * instance to operate.</p>
9593      *
9594      * @deprecated TODO Make private in 4.0.
9595      */
9596     @Deprecated
9597     public StringUtils() {
9598         // empty
9599     }
9600 
9601 }