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    *      https://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.CharBuffer;
21  import java.nio.charset.Charset;
22  import java.text.Normalizer;
23  import java.util.ArrayList;
24  import java.util.Arrays;
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  import java.util.stream.Collectors;
33  
34  import org.apache.commons.lang3.function.Suppliers;
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><strong>IsEmpty/IsBlank</strong>
44   *      - checks if a String contains text</li>
45   *  <li><strong>Trim/Strip</strong>
46   *      - removes leading and trailing whitespace</li>
47   *  <li><strong>Equals/Compare</strong>
48   *      - compares two strings in a null-safe manner</li>
49   *  <li><strong>startsWith</strong>
50   *      - check if a String starts with a prefix in a null-safe manner</li>
51   *  <li><strong>endsWith</strong>
52   *      - check if a String ends with a suffix in a null-safe manner</li>
53   *  <li><strong>IndexOf/LastIndexOf/Contains</strong>
54   *      - null-safe index-of checks
55   *  <li><strong>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</strong>
56   *      - index-of any of a set of Strings</li>
57   *  <li><strong>ContainsOnly/ContainsNone/ContainsAny</strong>
58   *      - checks if String contains only/none/any of these characters</li>
59   *  <li><strong>Substring/Left/Right/Mid</strong>
60   *      - null-safe substring extractions</li>
61   *  <li><strong>SubstringBefore/SubstringAfter/SubstringBetween</strong>
62   *      - substring extraction relative to other strings</li>
63   *  <li><strong>Split/Join</strong>
64   *      - splits a String into an array of substrings and vice versa</li>
65   *  <li><strong>Remove/Delete</strong>
66   *      - removes part of a String</li>
67   *  <li><strong>Replace/Overlay</strong>
68   *      - Searches a String and replaces one String with another</li>
69   *  <li><strong>Chomp/Chop</strong>
70   *      - removes the last part of a String</li>
71   *  <li><strong>AppendIfMissing</strong>
72   *      - appends a suffix to the end of the String if not present</li>
73   *  <li><strong>PrependIfMissing</strong>
74   *      - prepends a prefix to the start of the String if not present</li>
75   *  <li><strong>LeftPad/RightPad/Center/Repeat</strong>
76   *      - pads a String</li>
77   *  <li><strong>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</strong>
78   *      - changes the case of a String</li>
79   *  <li><strong>CountMatches</strong>
80   *      - counts the number of occurrences of one String in another</li>
81   *  <li><strong>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</strong>
82   *      - checks the characters in a String</li>
83   *  <li><strong>DefaultString</strong>
84   *      - protects against a null input String</li>
85   *  <li><strong>Rotate</strong>
86   *      - rotate (circular shift) a String</li>
87   *  <li><strong>Reverse/ReverseDelimited</strong>
88   *      - reverses a String</li>
89   *  <li><strong>Abbreviate</strong>
90   *      - abbreviates a string using ellipses or another given String</li>
91   *  <li><strong>Difference</strong>
92   *      - compares Strings and reports on their differences</li>
93   *  <li><strong>LevenshteinDistance</strong>
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      * This is a 3 character version of an ellipsis. There is a Unicode character for a HORIZONTAL ELLIPSIS, U+2026 … this isn't it.
145      */
146     private static final String ELLIPSIS3 = "...";
147 
148     /**
149      * A String for a space character.
150      *
151      * @since 3.2
152      */
153     public static final String SPACE = " ";
154 
155     /**
156      * The empty String {@code ""}.
157      * @since 2.0
158      */
159     public static final String EMPTY = "";
160 
161     /**
162      * The null String {@code null}. Package-private only.
163      */
164     static final String NULL = null;
165 
166     /**
167      * A String for linefeed LF ("\n").
168      *
169      * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
170      *      for Character and String Literals</a>
171      * @since 3.2
172      */
173     public static final String LF = "\n";
174 
175     /**
176      * A String for carriage return CR ("\r").
177      *
178      * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
179      *      for Character and String Literals</a>
180      * @since 3.2
181      */
182     public static final String CR = "\r";
183 
184     /**
185      * Represents a failed index search.
186      * @since 2.1
187      */
188     public static final int INDEX_NOT_FOUND = -1;
189 
190     /**
191      * The maximum size to which the padding constant(s) can expand.
192      */
193     private static final int PAD_LIMIT = 8192;
194 
195     /**
196      * The default maximum depth at which recursive replacement will continue until no further search replacements are possible.
197      */
198     private static final int DEFAULT_TTL = 5;
199 
200     /**
201      * Pattern used in {@link #stripAccents(String)}.
202      */
203     private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
204 
205     /**
206      * Abbreviates a String using ellipses. This will turn
207      * "Now is the time for all good men" into "Now is the time for..."
208      *
209      * <p>Specifically:</p>
210      * <ul>
211      *   <li>If the number of characters in {@code str} is less than or equal to
212      *       {@code maxWidth}, return {@code str}.</li>
213      *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
214      *   <li>If {@code maxWidth} is less than {@code 4}, throw an
215      *       {@link IllegalArgumentException}.</li>
216      *   <li>In no case will it return a String of length greater than
217      *       {@code maxWidth}.</li>
218      * </ul>
219      *
220      * <pre>
221      * StringUtils.abbreviate(null, *)      = null
222      * StringUtils.abbreviate("", 4)        = ""
223      * StringUtils.abbreviate("abcdefg", 6) = "abc..."
224      * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
225      * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
226      * StringUtils.abbreviate("abcdefg", 4) = "a..."
227      * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
228      * </pre>
229      *
230      * @param str  the String to check, may be null.
231      * @param maxWidth  maximum length of result String, must be at least 4.
232      * @return abbreviated String, {@code null} if null String input.
233      * @throws IllegalArgumentException if the width is too small.
234      * @since 2.0
235      */
236     public static String abbreviate(final String str, final int maxWidth) {
237         return abbreviate(str, ELLIPSIS3, 0, maxWidth);
238     }
239 
240     /**
241      * Abbreviates a String using ellipses. This will turn "Now is the time for all good men" into "...is the time for..."
242      *
243      * <p>
244      * Works like {@code abbreviate(String, int)}, but allows you to specify a "left edge" offset. Note that this left edge is not necessarily going to be the
245      * leftmost character in the result, or the first character following the ellipses, but it will appear somewhere in the result.
246      *
247      * <p>
248      * In no case will it return a String of length greater than {@code maxWidth}.
249      * </p>
250      *
251      * <pre>
252      * StringUtils.abbreviate(null, *, *)                = null
253      * StringUtils.abbreviate("", 0, 4)                  = ""
254      * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
255      * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
256      * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
257      * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
258      * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
259      * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
260      * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
261      * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
262      * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
263      * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
264      * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
265      * </pre>
266      *
267      * @param str      the String to check, may be null.
268      * @param offset   left edge of source String.
269      * @param maxWidth maximum length of result String, must be at least 4.
270      * @return abbreviated String, {@code null} if null String input.
271      * @throws IllegalArgumentException if the width is too small.
272      * @since 2.0
273      */
274     public static String abbreviate(final String str, final int offset, final int maxWidth) {
275         return abbreviate(str, ELLIPSIS3, offset, maxWidth);
276     }
277 
278     /**
279      * Abbreviates a String using another given String as replacement marker. This will turn "Now is the time for all good men" into "Now is the time for..." if
280      * "..." was defined as the replacement marker.
281      *
282      * <p>
283      * Specifically:
284      * </p>
285      * <ul>
286      * <li>If the number of characters in {@code str} is less than or equal to {@code maxWidth}, return {@code str}.</li>
287      * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
288      * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an {@link IllegalArgumentException}.</li>
289      * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
290      * </ul>
291      *
292      * <pre>
293      * StringUtils.abbreviate(null, "...", *)      = null
294      * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
295      * StringUtils.abbreviate("", "...", 4)        = ""
296      * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
297      * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
298      * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
299      * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
300      * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
301      * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
302      * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
303      * </pre>
304      *
305      * @param str          the String to check, may be null.
306      * @param abbrevMarker the String used as replacement marker.
307      * @param maxWidth     maximum length of result String, must be at least {@code abbrevMarker.length + 1}.
308      * @return abbreviated String, {@code null} if null String input.
309      * @throws IllegalArgumentException if the width is too small.
310      * @since 3.6
311      */
312     public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
313         return abbreviate(str, abbrevMarker, 0, maxWidth);
314     }
315 
316     /**
317      * Abbreviates a String using a given replacement marker. This will turn "Now is the time for all good men" into "...is the time for..." if "..." was
318      * defined as the replacement marker.
319      *
320      * <p>
321      * Works like {@code abbreviate(String, String, int)}, but allows you to specify a "left edge" offset. Note that this left edge is not necessarily going to
322      * be the leftmost character in the result, or the first character following the replacement marker, but it will appear somewhere in the result.
323      *
324      * <p>
325      * In no case will it return a String of length greater than {@code maxWidth}.
326      * </p>
327      *
328      * <pre>
329      * StringUtils.abbreviate(null, null, *, *)                 = null
330      * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
331      * StringUtils.abbreviate("", "...", 0, 4)                  = ""
332      * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
333      * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
334      * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
335      * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
336      * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
337      * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
338      * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
339      * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
340      * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
341      * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
342      * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
343      * </pre>
344      *
345      * @param str          the String to check, may be null.
346      * @param abbrevMarker the String used as replacement marker.
347      * @param offset       left edge of source String.
348      * @param maxWidth     maximum length of result String, must be at least 4.
349      * @return abbreviated String, {@code null} if null String input.
350      * @throws IllegalArgumentException if the width is too small.
351      * @since 3.6
352      */
353     public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
354         if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
355             return substring(str, 0, maxWidth);
356         }
357         if (isAnyEmpty(str, abbrevMarker)) {
358             return str;
359         }
360         final int abbrevMarkerLength = abbrevMarker.length();
361         final int minAbbrevWidth = abbrevMarkerLength + 1;
362         final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
363 
364         if (maxWidth < minAbbrevWidth) {
365             throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
366         }
367         final int strLen = str.length();
368         if (strLen <= maxWidth) {
369             return str;
370         }
371         if (offset > strLen) {
372             offset = strLen;
373         }
374         if (strLen - offset < maxWidth - abbrevMarkerLength) {
375             offset = strLen - (maxWidth - abbrevMarkerLength);
376         }
377         if (offset <= abbrevMarkerLength + 1) {
378             return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
379         }
380         if (maxWidth < minAbbrevWidthOffset) {
381             throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
382         }
383         if (offset + maxWidth - abbrevMarkerLength < strLen) {
384             return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
385         }
386         return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
387     }
388 
389     /**
390      * Abbreviates a String to the length passed, replacing the middle characters with the supplied replacement String.
391      *
392      * <p>
393      * This abbreviation only occurs if the following criteria is met:
394      * </p>
395      * <ul>
396      * <li>Neither the String for abbreviation nor the replacement String are null or empty</li>
397      * <li>The length to truncate to is less than the length of the supplied String</li>
398      * <li>The length to truncate to is greater than 0</li>
399      * <li>The abbreviated String will have enough room for the length supplied replacement String and the first and last characters of the supplied String for
400      * abbreviation</li>
401      * </ul>
402      * <p>
403      * Otherwise, the returned String will be the same as the supplied String for abbreviation.
404      * </p>
405      *
406      * <pre>
407      * StringUtils.abbreviateMiddle(null, null, 0)    = null
408      * StringUtils.abbreviateMiddle("abc", null, 0)   = "abc"
409      * StringUtils.abbreviateMiddle("abc", ".", 0)    = "abc"
410      * StringUtils.abbreviateMiddle("abc", ".", 3)    = "abc"
411      * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
412      * </pre>
413      *
414      * @param str    the String to abbreviate, may be null.
415      * @param middle the String to replace the middle characters with, may be null.
416      * @param length the length to abbreviate {@code str} to.
417      * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
418      * @since 2.5
419      */
420     public static String abbreviateMiddle(final String str, final String middle, final int length) {
421         if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length() + 2) {
422             return str;
423         }
424         final int targetSting = length - middle.length();
425         final int startOffset = targetSting / 2 + targetSting % 2;
426         final int endOffset = str.length() - targetSting / 2;
427         return str.substring(0, startOffset) + middle + str.substring(endOffset);
428     }
429 
430     /**
431      * Appends the suffix to the end of the string if the string does not already end with any of the suffixes.
432      *
433      * <pre>
434      * StringUtils.appendIfMissing(null, null)      = null
435      * StringUtils.appendIfMissing("abc", null)     = "abc"
436      * StringUtils.appendIfMissing("", "xyz"        = "xyz"
437      * StringUtils.appendIfMissing("abc", "xyz")    = "abcxyz"
438      * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
439      * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
440      * </pre>
441      * <p>
442      * With additional suffixes,
443      * </p>
444      *
445      * <pre>
446      * StringUtils.appendIfMissing(null, null, null)       = null
447      * StringUtils.appendIfMissing("abc", null, null)      = "abc"
448      * StringUtils.appendIfMissing("", "xyz", null)        = "xyz"
449      * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
450      * StringUtils.appendIfMissing("abc", "xyz", "")       = "abc"
451      * StringUtils.appendIfMissing("abc", "xyz", "mno")    = "abcxyz"
452      * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
453      * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
454      * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
455      * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
456      * </pre>
457      *
458      * @param str      The string.
459      * @param suffix   The suffix to append to the end of the string.
460      * @param suffixes Additional suffixes that are valid terminators.
461      * @return A new String if suffix was appended, the same string otherwise.
462      * @since 3.2
463      * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CS.appendIfMissing(String, CharSequence, CharSequence...)}
464      */
465     @Deprecated
466     public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
467         return Strings.CS.appendIfMissing(str, suffix, suffixes);
468     }
469 
470     /**
471      * Appends the suffix to the end of the string if the string does not
472      * already end, case-insensitive, with any of the suffixes.
473      *
474      * <pre>
475      * StringUtils.appendIfMissingIgnoreCase(null, null)      = null
476      * StringUtils.appendIfMissingIgnoreCase("abc", null)     = "abc"
477      * StringUtils.appendIfMissingIgnoreCase("", "xyz")       = "xyz"
478      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz")    = "abcxyz"
479      * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
480      * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
481      * </pre>
482      * <p>With additional suffixes,</p>
483      * <pre>
484      * StringUtils.appendIfMissingIgnoreCase(null, null, null)       = null
485      * StringUtils.appendIfMissingIgnoreCase("abc", null, null)      = "abc"
486      * StringUtils.appendIfMissingIgnoreCase("", "xyz", null)        = "xyz"
487      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
488      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "")       = "abc"
489      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno")    = "abcxyz"
490      * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
491      * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
492      * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
493      * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
494      * </pre>
495      *
496      * @param str The string.
497      * @param suffix The suffix to append to the end of the string.
498      * @param suffixes Additional suffixes that are valid terminators.
499      * @return A new String if suffix was appended, the same string otherwise.
500      * @since 3.2
501      * @deprecated Use {@link Strings#appendIfMissing(String, CharSequence, CharSequence...) Strings.CI.appendIfMissing(String, CharSequence, CharSequence...)}
502      */
503     @Deprecated
504     public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
505         return Strings.CI.appendIfMissing(str, suffix, suffixes);
506     }
507 
508     /**
509      * Capitalizes a String changing the first character to title case as per {@link Character#toTitleCase(int)}. No other characters are changed.
510      *
511      * <p>
512      * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}. A {@code null} input String returns {@code null}.
513      * </p>
514      *
515      * <pre>
516      * StringUtils.capitalize(null)    = null
517      * StringUtils.capitalize("")      = ""
518      * StringUtils.capitalize("cat")   = "Cat"
519      * StringUtils.capitalize("cAt")   = "CAt"
520      * StringUtils.capitalize("'cat'") = "'cat'"
521      * </pre>
522      *
523      * @param str the String to capitalize, may be null.
524      * @return the capitalized String, {@code null} if null String input.
525      * @see org.apache.commons.text.WordUtils#capitalize(String)
526      * @see #uncapitalize(String)
527      * @since 2.0
528      */
529     public static String capitalize(final String str) {
530         if (isEmpty(str)) {
531             return str;
532         }
533         final int firstCodepoint = str.codePointAt(0);
534         final int newCodePoint = Character.toTitleCase(firstCodepoint);
535         if (firstCodepoint == newCodePoint) {
536             // already capitalized
537             return str;
538         }
539         final int[] newCodePoints = str.codePoints().toArray();
540         newCodePoints[0] = newCodePoint; // copy the first code point
541         return new String(newCodePoints, 0, newCodePoints.length);
542     }
543 
544     /**
545      * Centers a String in a larger String of size {@code size} using the space character (' ').
546      *
547      * <p>
548      * If the size is less than the String length, the original String is returned. A {@code null} String returns {@code null}. A negative size is treated as
549      * zero.
550      * </p>
551      *
552      * <p>
553      * Equivalent to {@code center(str, size, " ")}.
554      * </p>
555      *
556      * <pre>
557      * StringUtils.center(null, *)   = null
558      * StringUtils.center("", 4)     = "    "
559      * StringUtils.center("ab", -1)  = "ab"
560      * StringUtils.center("ab", 4)   = " ab "
561      * StringUtils.center("abcd", 2) = "abcd"
562      * StringUtils.center("a", 4)    = " a  "
563      * </pre>
564      *
565      * @param str  the String to center, may be null.
566      * @param size the int size of new String, negative treated as zero.
567      * @return centered String, {@code null} if null String input.
568      */
569     public static String center(final String str, final int size) {
570         return center(str, size, ' ');
571     }
572 
573     /**
574      * Centers a String in a larger String of size {@code size}. Uses a supplied character as the value to pad the String with.
575      *
576      * <p>
577      * If the size is less than the String length, the String is returned. A {@code null} String returns {@code null}. A negative size is treated as zero.
578      * </p>
579      *
580      * <pre>
581      * StringUtils.center(null, *, *)     = null
582      * StringUtils.center("", 4, ' ')     = "    "
583      * StringUtils.center("ab", -1, ' ')  = "ab"
584      * StringUtils.center("ab", 4, ' ')   = " ab "
585      * StringUtils.center("abcd", 2, ' ') = "abcd"
586      * StringUtils.center("a", 4, ' ')    = " a  "
587      * StringUtils.center("a", 4, 'y')    = "yayy"
588      * </pre>
589      *
590      * @param str     the String to center, may be null.
591      * @param size    the int size of new String, negative treated as zero.
592      * @param padChar the character to pad the new String with.
593      * @return centered String, {@code null} if null String input.
594      * @since 2.0
595      */
596     public static String center(String str, final int size, final char padChar) {
597         if (str == null || size <= 0) {
598             return str;
599         }
600         final int strLen = str.length();
601         final int pads = size - strLen;
602         if (pads <= 0) {
603             return str;
604         }
605         str = leftPad(str, strLen + pads / 2, padChar);
606         return rightPad(str, size, padChar);
607     }
608 
609     /**
610      * Centers a String in a larger String of size {@code size}. Uses a supplied String as the value to pad the String with.
611      *
612      * <p>
613      * If the size is less than the String length, the String is returned. A {@code null} String returns {@code null}. A negative size is treated as zero.
614      * </p>
615      *
616      * <pre>
617      * StringUtils.center(null, *, *)     = null
618      * StringUtils.center("", 4, " ")     = "    "
619      * StringUtils.center("ab", -1, " ")  = "ab"
620      * StringUtils.center("ab", 4, " ")   = " ab "
621      * StringUtils.center("abcd", 2, " ") = "abcd"
622      * StringUtils.center("a", 4, " ")    = " a  "
623      * StringUtils.center("a", 4, "yz")   = "yayz"
624      * StringUtils.center("abc", 7, null) = "  abc  "
625      * StringUtils.center("abc", 7, "")   = "  abc  "
626      * </pre>
627      *
628      * @param str    the String to center, may be null.
629      * @param size   the int size of new String, negative treated as zero.
630      * @param padStr the String to pad the new String with, must not be null or empty.
631      * @return centered String, {@code null} if null String input.
632      * @throws IllegalArgumentException if padStr is {@code null} or empty.
633      */
634     public static String center(String str, final int size, String padStr) {
635         if (str == null || size <= 0) {
636             return str;
637         }
638         if (isEmpty(padStr)) {
639             padStr = SPACE;
640         }
641         final int strLen = str.length();
642         final int pads = size - strLen;
643         if (pads <= 0) {
644             return str;
645         }
646         str = leftPad(str, strLen + pads / 2, padStr);
647         return rightPad(str, size, padStr);
648     }
649 
650     /**
651      * Removes one newline from end of a String if it's there, otherwise leave it alone. A newline is &quot;{@code \n}&quot;, &quot;{@code \r}&quot;, or
652      * &quot;{@code \r\n}&quot;.
653      *
654      * <p>
655      * NOTE: This method changed in 2.0. It now more closely matches Perl chomp.
656      * </p>
657      *
658      * <pre>
659      * StringUtils.chomp(null)          = null
660      * StringUtils.chomp("")            = ""
661      * StringUtils.chomp("abc \r")      = "abc "
662      * StringUtils.chomp("abc\n")       = "abc"
663      * StringUtils.chomp("abc\r\n")     = "abc"
664      * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
665      * StringUtils.chomp("abc\n\r")     = "abc\n"
666      * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
667      * StringUtils.chomp("\r")          = ""
668      * StringUtils.chomp("\n")          = ""
669      * StringUtils.chomp("\r\n")        = ""
670      * </pre>
671      *
672      * @param str the String to chomp a newline from, may be null.
673      * @return String without newline, {@code null} if null String input.
674      */
675     public static String chomp(final String str) {
676         if (isEmpty(str)) {
677             return str;
678         }
679         if (str.length() == 1) {
680             final char ch = str.charAt(0);
681             if (ch == CharUtils.CR || ch == CharUtils.LF) {
682                 return EMPTY;
683             }
684             return str;
685         }
686         int lastIdx = str.length() - 1;
687         final char last = str.charAt(lastIdx);
688         if (last == CharUtils.LF) {
689             if (str.charAt(lastIdx - 1) == CharUtils.CR) {
690                 lastIdx--;
691             }
692         } else if (last != CharUtils.CR) {
693             lastIdx++;
694         }
695         return str.substring(0, lastIdx);
696     }
697 
698     /**
699      * Removes {@code separator} from the end of {@code str} if it's there, otherwise leave it alone.
700      *
701      * <p>
702      * NOTE: This method changed in version 2.0. It now more closely matches Perl chomp. For the previous behavior, use
703      * {@link #substringBeforeLast(String, String)}. This method uses {@link String#endsWith(String)}.
704      * </p>
705      *
706      * <pre>
707      * StringUtils.chomp(null, *)         = null
708      * StringUtils.chomp("", *)           = ""
709      * StringUtils.chomp("foobar", "bar") = "foo"
710      * StringUtils.chomp("foobar", "baz") = "foobar"
711      * StringUtils.chomp("foo", "foo")    = ""
712      * StringUtils.chomp("foo ", "foo")   = "foo "
713      * StringUtils.chomp(" foo", "foo")   = " "
714      * StringUtils.chomp("foo", "foooo")  = "foo"
715      * StringUtils.chomp("foo", "")       = "foo"
716      * StringUtils.chomp("foo", null)     = "foo"
717      * </pre>
718      *
719      * @param str       the String to chomp from, may be null.
720      * @param separator separator String, may be null.
721      * @return String without trailing separator, {@code null} if null String input.
722      * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead.
723      */
724     @Deprecated
725     public static String chomp(final String str, final String separator) {
726         return Strings.CS.removeEnd(str, separator);
727     }
728 
729     /**
730      * Removes the last character from a String.
731      *
732      * <p>
733      * If the String ends in {@code \r\n}, then remove both of them.
734      * </p>
735      *
736      * <pre>
737      * StringUtils.chop(null)          = null
738      * StringUtils.chop("")            = ""
739      * StringUtils.chop("abc \r")      = "abc "
740      * StringUtils.chop("abc\n")       = "abc"
741      * StringUtils.chop("abc\r\n")     = "abc"
742      * StringUtils.chop("abc")         = "ab"
743      * StringUtils.chop("abc\nabc")    = "abc\nab"
744      * StringUtils.chop("a")           = ""
745      * StringUtils.chop("\r")          = ""
746      * StringUtils.chop("\n")          = ""
747      * StringUtils.chop("\r\n")        = ""
748      * </pre>
749      *
750      * @param str the String to chop last character from, may be null.
751      * @return String without last character, {@code null} if null String input.
752      */
753     public static String chop(final String str) {
754         if (str == null) {
755             return null;
756         }
757         final int strLen = str.length();
758         if (strLen < 2) {
759             return EMPTY;
760         }
761         final int lastIdx = strLen - 1;
762         final String ret = str.substring(0, lastIdx);
763         final char last = str.charAt(lastIdx);
764         if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
765             return ret.substring(0, lastIdx - 1);
766         }
767         return ret;
768     }
769 
770     /**
771      * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
772      * <ul>
773      * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
774      * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
775      * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
776      * </ul>
777      *
778      * <p>
779      * This is a {@code null} safe version of:
780      * </p>
781      *
782      * <pre>
783      * str1.compareTo(str2)
784      * </pre>
785      *
786      * <p>
787      * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal.
788      * </p>
789      *
790      * <pre>{@code
791      * StringUtils.compare(null, null)   = 0
792      * StringUtils.compare(null , "a")   < 0
793      * StringUtils.compare("a", null)   > 0
794      * StringUtils.compare("abc", "abc") = 0
795      * StringUtils.compare("a", "b")     < 0
796      * StringUtils.compare("b", "a")     > 0
797      * StringUtils.compare("a", "B")     > 0
798      * StringUtils.compare("ab", "abc")  < 0
799      * }</pre>
800      *
801      * @param str1 the String to compare from.
802      * @param str2 the String to compare to
803      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
804      * @see #compare(String, String, boolean)
805      * @see String#compareTo(String)
806      * @since 3.5
807      * @deprecated Use {@link Strings#compare(String, String) Strings.CS.compare(String, String)}
808      */
809     @Deprecated
810     public static int compare(final String str1, final String str2) {
811         return Strings.CS.compare(str1, str2);
812     }
813 
814     /**
815      * Compares two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
816      * <ul>
817      * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
818      * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
819      * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
820      * </ul>
821      *
822      * <p>
823      * This is a {@code null} safe version of :
824      * </p>
825      *
826      * <pre>
827      * str1.compareTo(str2)
828      * </pre>
829      *
830      * <p>
831      * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal.
832      * </p>
833      *
834      * <pre>{@code
835      * StringUtils.compare(null, null, *)     = 0
836      * StringUtils.compare(null , "a", true)  < 0
837      * StringUtils.compare(null , "a", false) > 0
838      * StringUtils.compare("a", null, true)   > 0
839      * StringUtils.compare("a", null, false)  < 0
840      * StringUtils.compare("abc", "abc", *)   = 0
841      * StringUtils.compare("a", "b", *)       < 0
842      * StringUtils.compare("b", "a", *)       > 0
843      * StringUtils.compare("a", "B", *)       > 0
844      * StringUtils.compare("ab", "abc", *)    < 0
845      * }</pre>
846      *
847      * @param str1       the String to compare from.
848      * @param str2       the String to compare to.
849      * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
850      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}.
851      * @see String#compareTo(String)
852      * @since 3.5
853      */
854     public static int compare(final String str1, final String str2, final boolean nullIsLess) {
855         if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
856             return 0;
857         }
858         if (str1 == null) {
859             return nullIsLess ? -1 : 1;
860         }
861         if (str2 == null) {
862             return nullIsLess ? 1 : -1;
863         }
864         return str1.compareTo(str2);
865     }
866 
867     /**
868      * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
869      * <ul>
870      * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
871      * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
872      * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
873      * </ul>
874      *
875      * <p>
876      * This is a {@code null} safe version of:
877      * </p>
878      *
879      * <pre>
880      * str1.compareToIgnoreCase(str2)
881      * </pre>
882      *
883      * <p>
884      * {@code null} value is considered less than non-{@code null} value. Two {@code null} references are considered equal. Comparison is case insensitive.
885      * </p>
886      *
887      * <pre>{@code
888      * StringUtils.compareIgnoreCase(null, null)   = 0
889      * StringUtils.compareIgnoreCase(null , "a")   < 0
890      * StringUtils.compareIgnoreCase("a", null)    > 0
891      * StringUtils.compareIgnoreCase("abc", "abc") = 0
892      * StringUtils.compareIgnoreCase("abc", "ABC") = 0
893      * StringUtils.compareIgnoreCase("a", "b")     < 0
894      * StringUtils.compareIgnoreCase("b", "a")     > 0
895      * StringUtils.compareIgnoreCase("a", "B")     < 0
896      * StringUtils.compareIgnoreCase("A", "b")     < 0
897      * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
898      * }</pre>
899      *
900      * @param str1 the String to compare from.
901      * @param str2 the String to compare to.
902      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
903      * @see #compareIgnoreCase(String, String, boolean)
904      * @see String#compareToIgnoreCase(String)
905      * @since 3.5
906      * @deprecated Use {@link Strings#compare(String, String) Strings.CI.compare(String, String)}
907      */
908     @Deprecated
909     public static int compareIgnoreCase(final String str1, final String str2) {
910         return Strings.CI.compare(str1, str2);
911     }
912 
913     /**
914      * Compares two Strings lexicographically, ignoring case differences, as per {@link String#compareToIgnoreCase(String)}, returning :
915      * <ul>
916      * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
917      * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
918      * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
919      * </ul>
920      *
921      * <p>
922      * This is a {@code null} safe version of :
923      * </p>
924      * <pre>
925      * str1.compareToIgnoreCase(str2)
926      * </pre>
927      *
928      * <p>
929      * {@code null} inputs are handled according to the {@code nullIsLess} parameter. Two {@code null} references are considered equal. Comparison is case
930      * insensitive.
931      * </p>
932      *
933      * <pre>{@code
934      * StringUtils.compareIgnoreCase(null, null, *)     = 0
935      * StringUtils.compareIgnoreCase(null , "a", true)  < 0
936      * StringUtils.compareIgnoreCase(null , "a", false) > 0
937      * StringUtils.compareIgnoreCase("a", null, true)   > 0
938      * StringUtils.compareIgnoreCase("a", null, false)  < 0
939      * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
940      * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
941      * StringUtils.compareIgnoreCase("a", "b", *)       < 0
942      * StringUtils.compareIgnoreCase("b", "a", *)       > 0
943      * StringUtils.compareIgnoreCase("a", "B", *)       < 0
944      * StringUtils.compareIgnoreCase("A", "b", *)       < 0
945      * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
946      * }</pre>
947      *
948      * @param str1       the String to compare from.
949      * @param str2       the String to compare to.
950      * @param nullIsLess whether consider {@code null} value less than non-{@code null} value.
951      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, ignoring case differences.
952      * @see String#compareToIgnoreCase(String)
953      * @since 3.5
954      */
955     public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
956         if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
957             return 0;
958         }
959         if (str1 == null) {
960             return nullIsLess ? -1 : 1;
961         }
962         if (str2 == null) {
963             return nullIsLess ? 1 : -1;
964         }
965         return str1.compareToIgnoreCase(str2);
966     }
967 
968     /**
969      * Tests if CharSequence contains a search CharSequence, handling {@code null}.
970      * This method uses {@link String#indexOf(String)} if possible.
971      *
972      * <p>A {@code null} CharSequence will return {@code false}.</p>
973      *
974      * <pre>
975      * StringUtils.contains(null, *)     = false
976      * StringUtils.contains(*, null)     = false
977      * StringUtils.contains("", "")      = true
978      * StringUtils.contains("abc", "")   = true
979      * StringUtils.contains("abc", "a")  = true
980      * StringUtils.contains("abc", "z")  = false
981      * </pre>
982      *
983      * @param seq  the CharSequence to check, may be null
984      * @param searchSeq  the CharSequence to find, may be null
985      * @return true if the CharSequence contains the search CharSequence,
986      *  false if not or {@code null} string input
987      * @since 2.0
988      * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
989      * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CS.contains(CharSequence, CharSequence)}
990      */
991     @Deprecated
992     public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
993         return Strings.CS.contains(seq, searchSeq);
994     }
995 
996     /**
997      * Tests if CharSequence contains a search character, handling {@code null}. This method uses {@link String#indexOf(int)} if possible.
998      *
999      * <p>
1000      * A {@code null} or empty ("") CharSequence will return {@code false}.
1001      * </p>
1002      *
1003      * <pre>
1004      * StringUtils.contains(null, *)    = false
1005      * StringUtils.contains("", *)      = false
1006      * StringUtils.contains("abc", 'a') = true
1007      * StringUtils.contains("abc", 'z') = false
1008      * </pre>
1009      *
1010      * @param seq        the CharSequence to check, may be null
1011      * @param searchChar the character to find
1012      * @return true if the CharSequence contains the search character, false if not or {@code null} string input
1013      * @since 2.0
1014      * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1015      */
1016     public static boolean contains(final CharSequence seq, final int searchChar) {
1017         if (isEmpty(seq)) {
1018             return false;
1019         }
1020         return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1021     }
1022 
1023     /**
1024      * Tests if the CharSequence contains any character in the given set of characters.
1025      *
1026      * <p>
1027      * A {@code null} CharSequence will return {@code false}. A {@code null} or zero length search array will return {@code false}.
1028      * </p>
1029      *
1030      * <pre>
1031      * StringUtils.containsAny(null, *)                  = false
1032      * StringUtils.containsAny("", *)                    = false
1033      * StringUtils.containsAny(*, null)                  = false
1034      * StringUtils.containsAny(*, [])                    = false
1035      * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1036      * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1037      * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1038      * StringUtils.containsAny("aba", ['z'])             = false
1039      * </pre>
1040      *
1041      * @param cs          the CharSequence to check, may be null.
1042      * @param searchChars the chars to search for, may be null.
1043      * @return the {@code true} if any of the chars are found, {@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) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1060                         return true;
1061                     }
1062                 }
1063             }
1064         }
1065         return false;
1066     }
1067 
1068     /**
1069      * Tests if the CharSequence contains any character in the given set of characters.
1070      *
1071      * <p>
1072      * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return {@code false}.
1073      * </p>
1074      *
1075      * <pre>
1076      * StringUtils.containsAny(null, *)               = false
1077      * StringUtils.containsAny("", *)                 = false
1078      * StringUtils.containsAny(*, null)               = false
1079      * StringUtils.containsAny(*, "")                 = false
1080      * StringUtils.containsAny("zzabyycdxx", "za")    = true
1081      * StringUtils.containsAny("zzabyycdxx", "by")    = true
1082      * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1083      * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1084      * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1085      * StringUtils.containsAny("aba", "z")            = false
1086      * </pre>
1087      *
1088      * @param cs          the CharSequence to check, may be null.
1089      * @param searchChars the chars to search for, may be null.
1090      * @return the {@code true} if any of the chars are found, {@code false} if no match or null input.
1091      * @since 2.4
1092      * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1093      */
1094     public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1095         if (searchChars == null) {
1096             return false;
1097         }
1098         return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1099     }
1100 
1101     /**
1102      * Tests if the CharSequence contains any of the CharSequences in the given array.
1103      *
1104      * <p>
1105      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1106      * return {@code false}.
1107      * </p>
1108      *
1109      * <pre>
1110      * StringUtils.containsAny(null, *)            = false
1111      * StringUtils.containsAny("", *)              = false
1112      * StringUtils.containsAny(*, null)            = false
1113      * StringUtils.containsAny(*, [])              = false
1114      * StringUtils.containsAny("abcd", "ab", null) = true
1115      * StringUtils.containsAny("abcd", "ab", "cd") = true
1116      * StringUtils.containsAny("abc", "d", "abc")  = true
1117      * </pre>
1118      *
1119      * @param cs The CharSequence to check, may be null.
1120      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1121      *        null as well.
1122      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise.
1123      * @since 3.4
1124      * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CS.containsAny(CharSequence, CharSequence...)}
1125      */
1126     @Deprecated
1127     public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1128         return Strings.CS.containsAny(cs, searchCharSequences);
1129     }
1130 
1131     /**
1132      * Tests if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1133      *
1134      * <p>
1135      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1136      * return {@code false}.
1137      * </p>
1138      *
1139      * <pre>
1140      * StringUtils.containsAny(null, *)            = false
1141      * StringUtils.containsAny("", *)              = false
1142      * StringUtils.containsAny(*, null)            = false
1143      * StringUtils.containsAny(*, [])              = false
1144      * StringUtils.containsAny("abcd", "ab", null) = true
1145      * StringUtils.containsAny("abcd", "ab", "cd") = true
1146      * StringUtils.containsAny("abc", "d", "abc")  = true
1147      * StringUtils.containsAny("abc", "D", "ABC")  = true
1148      * StringUtils.containsAny("ABC", "d", "abc")  = true
1149      * </pre>
1150      *
1151      * @param cs The CharSequence to check, may be null.
1152      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1153      *        null as well.
1154      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1155      * @since 3.12.0
1156      * @deprecated Use {@link Strings#containsAny(CharSequence, CharSequence...) Strings.CI.containsAny(CharSequence, CharSequence...)}
1157      */
1158     @Deprecated
1159     public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1160         return Strings.CI.containsAny(cs, searchCharSequences);
1161     }
1162 
1163     /**
1164      * Tests if CharSequence contains a search CharSequence irrespective of case, handling {@code null}. Case-insensitivity is defined as by
1165      * {@link String#equalsIgnoreCase(String)}.
1166      *
1167      * <p>
1168      * A {@code null} CharSequence will return {@code false}.
1169      *
1170      * <pre>
1171      * StringUtils.containsIgnoreCase(null, *)    = false
1172      * StringUtils.containsIgnoreCase(*, null)    = false
1173      * StringUtils.containsIgnoreCase("", "")     = true
1174      * StringUtils.containsIgnoreCase("abc", "")  = true
1175      * StringUtils.containsIgnoreCase("abc", "a") = true
1176      * StringUtils.containsIgnoreCase("abc", "z") = false
1177      * StringUtils.containsIgnoreCase("abc", "A") = true
1178      * StringUtils.containsIgnoreCase("abc", "Z") = false
1179      * </pre>
1180      *
1181      * @param str       the CharSequence to check, may be null.
1182      * @param searchStr the CharSequence to find, may be null.
1183      * @return true if the CharSequence contains the search CharSequence irrespective of case or false if not or {@code null} string input.
1184      * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence).
1185      * @deprecated Use {@link Strings#contains(CharSequence, CharSequence) Strings.CI.contains(CharSequence, CharSequence)}
1186      */
1187     @Deprecated
1188     public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1189         return Strings.CI.contains(str, searchStr);
1190     }
1191 
1192     /**
1193      * Tests that the CharSequence does not contain certain characters.
1194      *
1195      * <p>
1196      * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty CharSequence (length()=0)
1197      * always returns true.
1198      * </p>
1199      *
1200      * <pre>
1201      * StringUtils.containsNone(null, *)       = true
1202      * StringUtils.containsNone(*, null)       = true
1203      * StringUtils.containsNone("", *)         = true
1204      * StringUtils.containsNone("ab", '')      = true
1205      * StringUtils.containsNone("abab", 'xyz') = true
1206      * StringUtils.containsNone("ab1", 'xyz')  = true
1207      * StringUtils.containsNone("abz", 'xyz')  = false
1208      * </pre>
1209      *
1210      * @param cs          the CharSequence to check, may be null.
1211      * @param searchChars an array of invalid chars, may be null.
1212      * @return true if it contains none of the invalid chars, or is null.
1213      * @since 2.0
1214      * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1215      */
1216     public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1217         if (cs == null || searchChars == null) {
1218             return true;
1219         }
1220         final int csLen = cs.length();
1221         final int csLast = csLen - 1;
1222         final int searchLen = searchChars.length;
1223         final int searchLast = searchLen - 1;
1224         for (int i = 0; i < csLen; i++) {
1225             final char ch = cs.charAt(i);
1226             for (int j = 0; j < searchLen; j++) {
1227                 if (searchChars[j] == ch) {
1228                     if (!Character.isHighSurrogate(ch) || j == searchLast || i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1229                         return false;
1230                     }
1231                 }
1232             }
1233         }
1234         return true;
1235     }
1236 
1237     /**
1238      * Tests that the CharSequence does not contain certain characters.
1239      *
1240      * <p>
1241      * A {@code null} CharSequence will return {@code true}. A {@code null} invalid character array will return {@code true}. An empty String ("") always
1242      * returns true.
1243      * </p>
1244      *
1245      * <pre>
1246      * StringUtils.containsNone(null, *)       = true
1247      * StringUtils.containsNone(*, null)       = true
1248      * StringUtils.containsNone("", *)         = true
1249      * StringUtils.containsNone("ab", "")      = true
1250      * StringUtils.containsNone("abab", "xyz") = true
1251      * StringUtils.containsNone("ab1", "xyz")  = true
1252      * StringUtils.containsNone("abz", "xyz")  = false
1253      * </pre>
1254      *
1255      * @param cs           the CharSequence to check, may be null.
1256      * @param invalidChars a String of invalid chars, may be null.
1257      * @return true if it contains none of the invalid chars, or is null.
1258      * @since 2.0
1259      * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1260      */
1261     public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1262         if (invalidChars == null) {
1263             return true;
1264         }
1265         return containsNone(cs, invalidChars.toCharArray());
1266     }
1267 
1268     /**
1269      * Tests if the CharSequence contains only certain characters.
1270      *
1271      * <p>
1272      * A {@code null} CharSequence will return {@code false}. A {@code null} valid character array will return {@code false}. An empty CharSequence (length()=0)
1273      * always returns {@code true}.
1274      * </p>
1275      *
1276      * <pre>
1277      * StringUtils.containsOnly(null, *)       = false
1278      * StringUtils.containsOnly(*, null)       = false
1279      * StringUtils.containsOnly("", *)         = true
1280      * StringUtils.containsOnly("ab", '')      = false
1281      * StringUtils.containsOnly("abab", 'abc') = true
1282      * StringUtils.containsOnly("ab1", 'abc')  = false
1283      * StringUtils.containsOnly("abz", 'abc')  = false
1284      * </pre>
1285      *
1286      * @param cs    the String to check, may be null.
1287      * @param valid an array of valid chars, may be null.
1288      * @return true if it only contains valid chars and is non-null.
1289      * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1290      */
1291     public static boolean containsOnly(final CharSequence cs, final char... valid) {
1292         // All these pre-checks are to maintain API with an older version
1293         if (valid == null || cs == null) {
1294             return false;
1295         }
1296         if (cs.length() == 0) {
1297             return true;
1298         }
1299         if (valid.length == 0) {
1300             return false;
1301         }
1302         return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1303     }
1304 
1305     /**
1306      * Tests if the CharSequence contains only certain characters.
1307      *
1308      * <p>
1309      * A {@code null} CharSequence will return {@code false}. A {@code null} valid character String will return {@code false}. An empty String (length()=0)
1310      * always returns {@code true}.
1311      * </p>
1312      *
1313      * <pre>
1314      * StringUtils.containsOnly(null, *)       = false
1315      * StringUtils.containsOnly(*, null)       = false
1316      * StringUtils.containsOnly("", *)         = true
1317      * StringUtils.containsOnly("ab", "")      = false
1318      * StringUtils.containsOnly("abab", "abc") = true
1319      * StringUtils.containsOnly("ab1", "abc")  = false
1320      * StringUtils.containsOnly("abz", "abc")  = false
1321      * </pre>
1322      *
1323      * @param cs         the CharSequence to check, may be null.
1324      * @param validChars a String of valid chars, may be null.
1325      * @return true if it only contains valid chars and is non-null.
1326      * @since 2.0
1327      * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1328      */
1329     public static boolean containsOnly(final CharSequence cs, final String validChars) {
1330         if (cs == null || validChars == null) {
1331             return false;
1332         }
1333         return containsOnly(cs, validChars.toCharArray());
1334     }
1335 
1336     /**
1337      * Tests whether the given CharSequence contains any whitespace characters.
1338      *
1339      * <p>
1340      * Whitespace is defined by {@link Character#isWhitespace(char)}.
1341      * </p>
1342      *
1343      * <pre>
1344      * StringUtils.containsWhitespace(null)       = false
1345      * StringUtils.containsWhitespace("")         = false
1346      * StringUtils.containsWhitespace("ab")       = false
1347      * StringUtils.containsWhitespace(" ab")      = true
1348      * StringUtils.containsWhitespace("a b")      = true
1349      * StringUtils.containsWhitespace("ab ")      = true
1350      * </pre>
1351      *
1352      * @param seq the CharSequence to check (may be {@code null}).
1353      * @return {@code true} if the CharSequence is not empty and contains at least 1 (breaking) whitespace character.
1354      * @since 3.0
1355      */
1356     public static boolean containsWhitespace(final CharSequence seq) {
1357         if (isEmpty(seq)) {
1358             return false;
1359         }
1360         final int strLen = seq.length();
1361         for (int i = 0; i < strLen; i++) {
1362             if (Character.isWhitespace(seq.charAt(i))) {
1363                 return true;
1364             }
1365         }
1366         return false;
1367     }
1368 
1369     private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1370         for (int i = 0; i < decomposed.length(); i++) {
1371             final char charAt = decomposed.charAt(i);
1372             switch (charAt) {
1373             case '\u0141':
1374                 decomposed.setCharAt(i, 'L');
1375                 break;
1376             case '\u0142':
1377                 decomposed.setCharAt(i, 'l');
1378                 break;
1379             // D with stroke
1380             case '\u0110':
1381                 // LATIN CAPITAL LETTER D WITH STROKE
1382                 decomposed.setCharAt(i, 'D');
1383                 break;
1384             case '\u0111':
1385                 // LATIN SMALL LETTER D WITH STROKE
1386                 decomposed.setCharAt(i, 'd');
1387                 break;
1388             // I with bar
1389             case '\u0197':
1390                 decomposed.setCharAt(i, 'I');
1391                 break;
1392             case '\u0268':
1393                 decomposed.setCharAt(i, 'i');
1394                 break;
1395             case '\u1D7B':
1396                 decomposed.setCharAt(i, 'I');
1397                 break;
1398             case '\u1DA4':
1399                 decomposed.setCharAt(i, 'i');
1400                 break;
1401             case '\u1DA7':
1402                 decomposed.setCharAt(i, 'I');
1403                 break;
1404             // U with bar
1405             case '\u0244':
1406                 // LATIN CAPITAL LETTER U BAR
1407                 decomposed.setCharAt(i, 'U');
1408                 break;
1409             case '\u0289':
1410                 // LATIN SMALL LETTER U BAR
1411                 decomposed.setCharAt(i, 'u');
1412                 break;
1413             case '\u1D7E':
1414                 // LATIN SMALL CAPITAL LETTER U WITH STROKE
1415                 decomposed.setCharAt(i, 'U');
1416                 break;
1417             case '\u1DB6':
1418                 // MODIFIER LETTER SMALL U BAR
1419                 decomposed.setCharAt(i, 'u');
1420                 break;
1421             // T with stroke
1422             case '\u0166':
1423                 // LATIN CAPITAL LETTER T WITH STROKE
1424                 decomposed.setCharAt(i, 'T');
1425                 break;
1426             case '\u0167':
1427                 // LATIN SMALL LETTER T WITH STROKE
1428                 decomposed.setCharAt(i, 't');
1429                 break;
1430             default:
1431                 break;
1432             }
1433         }
1434     }
1435 
1436     /**
1437      * Counts how many times the char appears in the given string.
1438      *
1439      * <p>
1440      * A {@code null} or empty ("") String input returns {@code 0}.
1441      * </p>
1442      *
1443      * <pre>
1444      * StringUtils.countMatches(null, *)     = 0
1445      * StringUtils.countMatches("", *)       = 0
1446      * StringUtils.countMatches("abba", 0)   = 0
1447      * StringUtils.countMatches("abba", 'a') = 2
1448      * StringUtils.countMatches("abba", 'b') = 2
1449      * StringUtils.countMatches("abba", 'x') = 0
1450      * </pre>
1451      *
1452      * @param str the CharSequence to check, may be null.
1453      * @param ch  the char to count.
1454      * @return the number of occurrences, 0 if the CharSequence is {@code null}.
1455      * @since 3.4
1456      */
1457     public static int countMatches(final CharSequence str, final char ch) {
1458         if (isEmpty(str)) {
1459             return 0;
1460         }
1461         int count = 0;
1462         // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1463         for (int i = 0; i < str.length(); i++) {
1464             if (ch == str.charAt(i)) {
1465                 count++;
1466             }
1467         }
1468         return count;
1469     }
1470 
1471     /**
1472      * Counts how many times the substring appears in the larger string. Note that the code only counts non-overlapping matches.
1473      *
1474      * <p>
1475      * A {@code null} or empty ("") String input returns {@code 0}.
1476      * </p>
1477      *
1478      * <pre>
1479      * StringUtils.countMatches(null, *)        = 0
1480      * StringUtils.countMatches("", *)          = 0
1481      * StringUtils.countMatches("abba", null)   = 0
1482      * StringUtils.countMatches("abba", "")     = 0
1483      * StringUtils.countMatches("abba", "a")    = 2
1484      * StringUtils.countMatches("abba", "ab")   = 1
1485      * StringUtils.countMatches("abba", "xxx")  = 0
1486      * StringUtils.countMatches("ababa", "aba") = 1
1487      * </pre>
1488      *
1489      * @param str the CharSequence to check, may be null.
1490      * @param sub the substring to count, may be null.
1491      * @return the number of occurrences, 0 if either CharSequence is {@code null}.
1492      * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1493      */
1494     public static int countMatches(final CharSequence str, final CharSequence sub) {
1495         if (isEmpty(str) || isEmpty(sub)) {
1496             return 0;
1497         }
1498         int count = 0;
1499         int idx = 0;
1500         while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1501             count++;
1502             idx += sub.length();
1503         }
1504         return count;
1505     }
1506 
1507     /**
1508      * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
1509      * {@code null}), the value of {@code defaultStr}.
1510      *
1511      * <p>
1512      * Whitespace is defined by {@link Character#isWhitespace(char)}.
1513      * </p>
1514      *
1515      * <pre>
1516      * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1517      * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1518      * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1519      * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1520      * StringUtils.defaultIfBlank("", null)      = null
1521      * </pre>
1522      *
1523      * @param <T>        the specific kind of CharSequence.
1524      * @param str        the CharSequence to check, may be null.
1525      * @param defaultStr the default CharSequence to return if {@code str} is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code""}) or
1526      *                   {@code null}); may be null.
1527      * @return the passed in CharSequence, or the default.
1528      * @see StringUtils#defaultString(String, String)
1529      * @see #isBlank(CharSequence)
1530      */
1531     public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1532         return isBlank(str) ? defaultStr : str;
1533     }
1534 
1535     /**
1536      * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value of {@code defaultStr}.
1537      *
1538      * <pre>
1539      * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1540      * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1541      * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1542      * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1543      * StringUtils.defaultIfEmpty("", null)      = null
1544      * </pre>
1545      *
1546      * @param <T>        the specific kind of CharSequence.
1547      * @param str        the CharSequence to check, may be null.
1548      * @param defaultStr the default CharSequence to return if the input is empty ("") or {@code null}, may be null.
1549      * @return the passed in CharSequence, or the default.
1550      * @see StringUtils#defaultString(String, String)
1551      */
1552     public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1553         return isEmpty(str) ? defaultStr : str;
1554     }
1555 
1556     /**
1557      * Returns either the passed in String, or if the String is {@code null}, an empty String ("").
1558      *
1559      * <pre>
1560      * StringUtils.defaultString(null)  = ""
1561      * StringUtils.defaultString("")    = ""
1562      * StringUtils.defaultString("bat") = "bat"
1563      * </pre>
1564      *
1565      * @param str the String to check, may be null.
1566      * @return the passed in String, or the empty String if it was {@code null}.
1567      * @see Objects#toString(Object, String)
1568      * @see String#valueOf(Object)
1569      */
1570     public static String defaultString(final String str) {
1571         return Objects.toString(str, EMPTY);
1572     }
1573 
1574     /**
1575      * Returns either the given String, or if the String is {@code null}, {@code nullDefault}.
1576      *
1577      * <pre>
1578      * StringUtils.defaultString(null, "NULL")  = "NULL"
1579      * StringUtils.defaultString("", "NULL")    = ""
1580      * StringUtils.defaultString("bat", "NULL") = "bat"
1581      * </pre>
1582      * <p>
1583      * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1584      * </p>
1585      *
1586      * <pre>
1587      * Objects.toString(null, "NULL")  = "NULL"
1588      * Objects.toString("", "NULL")    = ""
1589      * Objects.toString("bat", "NULL") = "bat"
1590      * </pre>
1591      *
1592      * @param str         the String to check, may be null.
1593      * @param nullDefault the default String to return if the input is {@code null}, may be null.
1594      * @return the passed in String, or the default if it was {@code null}.
1595      * @see Objects#toString(Object, String)
1596      * @see String#valueOf(Object)
1597      * @deprecated Use {@link Objects#toString(Object, String)}
1598      */
1599     @Deprecated
1600     public static String defaultString(final String str, final String nullDefault) {
1601         return Objects.toString(str, nullDefault);
1602     }
1603 
1604     /**
1605      * Deletes all whitespaces from a String as defined by {@link Character#isWhitespace(char)}.
1606      *
1607      * <pre>
1608      * StringUtils.deleteWhitespace(null)         = null
1609      * StringUtils.deleteWhitespace("")           = ""
1610      * StringUtils.deleteWhitespace("abc")        = "abc"
1611      * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1612      * </pre>
1613      *
1614      * @param str the String to delete whitespace from, may be null.
1615      * @return the String without whitespaces, {@code null} if null String input.
1616      */
1617     public static String deleteWhitespace(final String str) {
1618         if (isEmpty(str)) {
1619             return str;
1620         }
1621         final int sz = str.length();
1622         final char[] chs = new char[sz];
1623         int count = 0;
1624         for (int i = 0; i < sz; i++) {
1625             if (!Character.isWhitespace(str.charAt(i))) {
1626                 chs[count++] = str.charAt(i);
1627             }
1628         }
1629         if (count == sz) {
1630             return str;
1631         }
1632         if (count == 0) {
1633             return EMPTY;
1634         }
1635         return new String(chs, 0, count);
1636     }
1637 
1638     /**
1639      * Compares two Strings, and returns the portion where they differ. More precisely, return the remainder of the second String, starting from where it's
1640      * different from the first. This means that the difference between "abc" and "ab" is the empty String and not "c".
1641      *
1642      * <p>
1643      * For example, {@code difference("i am a machine", "i am a robot") -> "robot"}.
1644      * </p>
1645      *
1646      * <pre>
1647      * StringUtils.difference(null, null)       = null
1648      * StringUtils.difference("", "")           = ""
1649      * StringUtils.difference("", "abc")        = "abc"
1650      * StringUtils.difference("abc", "")        = ""
1651      * StringUtils.difference("abc", "abc")     = ""
1652      * StringUtils.difference("abc", "ab")      = ""
1653      * StringUtils.difference("ab", "abxyz")    = "xyz"
1654      * StringUtils.difference("abcde", "abxyz") = "xyz"
1655      * StringUtils.difference("abcde", "xyz")   = "xyz"
1656      * </pre>
1657      *
1658      * @param str1 the first String, may be null.
1659      * @param str2 the second String, may be null.
1660      * @return the portion of str2 where it differs from str1; returns the empty String if they are equal.
1661      * @see #indexOfDifference(CharSequence,CharSequence)
1662      * @since 2.0
1663      */
1664     public static String difference(final String str1, final String str2) {
1665         if (str1 == null) {
1666             return str2;
1667         }
1668         if (str2 == null) {
1669             return str1;
1670         }
1671         final int at = indexOfDifference(str1, str2);
1672         if (at == INDEX_NOT_FOUND) {
1673             return EMPTY;
1674         }
1675         return str2.substring(at);
1676     }
1677 
1678     /**
1679      * Tests if a CharSequence ends with a specified suffix.
1680      *
1681      * <p>
1682      * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
1683      * </p>
1684      *
1685      * <pre>
1686      * StringUtils.endsWith(null, null)      = true
1687      * StringUtils.endsWith(null, "def")     = false
1688      * StringUtils.endsWith("abcdef", null)  = false
1689      * StringUtils.endsWith("abcdef", "def") = true
1690      * StringUtils.endsWith("ABCDEF", "def") = false
1691      * StringUtils.endsWith("ABCDEF", "cde") = false
1692      * StringUtils.endsWith("ABCDEF", "")    = true
1693      * </pre>
1694      *
1695      * @param str    the CharSequence to check, may be null.
1696      * @param suffix the suffix to find, may be null.
1697      * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or both {@code null}.
1698      * @see String#endsWith(String)
1699      * @since 2.4
1700      * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1701      * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CS.endsWith(CharSequence, CharSequence)}
1702      */
1703     @Deprecated
1704     public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1705         return Strings.CS.endsWith(str, suffix);
1706     }
1707 
1708     /**
1709      * Tests if a CharSequence ends with any of the provided case-sensitive suffixes.
1710      *
1711      * <pre>
1712      * StringUtils.endsWithAny(null, null)                  = false
1713      * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1714      * StringUtils.endsWithAny("abcxyz", null)              = false
1715      * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1716      * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1717      * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1718      * StringUtils.endsWithAny("abcXYZ", "def", "XYZ")      = true
1719      * StringUtils.endsWithAny("abcXYZ", "def", "xyz")      = false
1720      * </pre>
1721      *
1722      * @param sequence      the CharSequence to check, may be null.
1723      * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}.
1724      * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} ends in any
1725      *         of the provided case-sensitive {@code searchStrings}.
1726      * @see StringUtils#endsWith(CharSequence, CharSequence)
1727      * @since 3.0
1728      * @deprecated Use {@link Strings#endsWithAny(CharSequence, CharSequence...) Strings.CS.endsWithAny(CharSequence, CharSequence...)}
1729      */
1730     @Deprecated
1731     public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1732         return Strings.CS.endsWithAny(sequence, searchStrings);
1733     }
1734 
1735     /**
1736      * Case-insensitive check if a CharSequence ends with a specified suffix.
1737      *
1738      * <p>
1739      * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
1740      * </p>
1741      *
1742      * <pre>
1743      * StringUtils.endsWithIgnoreCase(null, null)      = true
1744      * StringUtils.endsWithIgnoreCase(null, "def")     = false
1745      * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1746      * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1747      * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1748      * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1749      * </pre>
1750      *
1751      * @param str    the CharSequence to check, may be null
1752      * @param suffix the suffix to find, may be null
1753      * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or both {@code null}
1754      * @see String#endsWith(String)
1755      * @since 2.4
1756      * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1757      * @deprecated Use {@link Strings#endsWith(CharSequence, CharSequence) Strings.CI.endsWith(CharSequence, CharSequence)}
1758      */
1759     @Deprecated
1760     public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1761         return Strings.CI.endsWith(str, suffix);
1762     }
1763 
1764     /**
1765      * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters.
1766      *
1767      * <p>
1768      * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is <strong>case-sensitive</strong>.
1769      * </p>
1770      *
1771      * <pre>
1772      * StringUtils.equals(null, null)   = true
1773      * StringUtils.equals(null, "abc")  = false
1774      * StringUtils.equals("abc", null)  = false
1775      * StringUtils.equals("abc", "abc") = true
1776      * StringUtils.equals("abc", "ABC") = false
1777      * </pre>
1778      *
1779      * @param cs1 the first CharSequence, may be {@code null}.
1780      * @param cs2 the second CharSequence, may be {@code null}.
1781      * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}.
1782      * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1783      * @see Object#equals(Object)
1784      * @see #equalsIgnoreCase(CharSequence, CharSequence)
1785      * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CS.equals(CharSequence, CharSequence)}
1786      */
1787     @Deprecated
1788     public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1789         return Strings.CS.equals(cs1, cs2);
1790     }
1791 
1792     /**
1793      * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, returning {@code true} if the {@code string} is equal to any of the
1794      * {@code searchStrings}.
1795      *
1796      * <pre>
1797      * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1798      * StringUtils.equalsAny(null, null, null)    = true
1799      * StringUtils.equalsAny(null, "abc", "def")  = false
1800      * StringUtils.equalsAny("abc", null, "def")  = false
1801      * StringUtils.equalsAny("abc", "abc", "def") = true
1802      * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1803      * </pre>
1804      *
1805      * @param string        to compare, may be {@code null}.
1806      * @param searchStrings a vararg of strings, may be {@code null}.
1807      * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings}; {@code false} if {@code searchStrings} is
1808      *         null or contains no matches.
1809      * @since 3.5
1810      * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CS.equalsAny(CharSequence, CharSequence...)}
1811      */
1812     @Deprecated
1813     public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1814         return Strings.CS.equalsAny(string, searchStrings);
1815     }
1816 
1817     /**
1818      * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1819      * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1820      *
1821      * <pre>
1822      * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1823      * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1824      * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1825      * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1826      * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1827      * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1828      * </pre>
1829      *
1830      * @param string to compare, may be {@code null}.
1831      * @param searchStrings a vararg of strings, may be {@code null}.
1832      * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1833      * {@code false} if {@code searchStrings} is null or contains no matches.
1834      * @since 3.5
1835      * @deprecated Use {@link Strings#equalsAny(CharSequence, CharSequence...) Strings.CI-.equalsAny(CharSequence, CharSequence...)}
1836      */
1837     @Deprecated
1838     public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1839         return Strings.CI.equalsAny(string, searchStrings);
1840     }
1841 
1842     /**
1843      * Compares two CharSequences, returning {@code true} if they represent equal sequences of characters, ignoring case.
1844      *
1845      * <p>
1846      * {@code null}s are handled without exceptions. Two {@code null} references are considered equal. The comparison is <strong>case insensitive</strong>.
1847      * </p>
1848      *
1849      * <pre>
1850      * StringUtils.equalsIgnoreCase(null, null)   = true
1851      * StringUtils.equalsIgnoreCase(null, "abc")  = false
1852      * StringUtils.equalsIgnoreCase("abc", null)  = false
1853      * StringUtils.equalsIgnoreCase("abc", "abc") = true
1854      * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1855      * </pre>
1856      *
1857      * @param cs1 the first CharSequence, may be {@code null}.
1858      * @param cs2 the second CharSequence, may be {@code null}.
1859      * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}.
1860      * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1861      * @see #equals(CharSequence, CharSequence)
1862      * @deprecated Use {@link Strings#equals(CharSequence, CharSequence) Strings.CI.equals(CharSequence, CharSequence)}
1863      */
1864     @Deprecated
1865     public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1866         return Strings.CI.equals(cs1, cs2);
1867     }
1868 
1869     /**
1870      * Returns the first value in the array which is not empty (""), {@code null} or whitespace only.
1871      *
1872      * <p>
1873      * Whitespace is defined by {@link Character#isWhitespace(char)}.
1874      * </p>
1875      *
1876      * <p>
1877      * If all values are blank or the array is {@code null} or empty then {@code null} is returned.
1878      * </p>
1879      *
1880      * <pre>
1881      * StringUtils.firstNonBlank(null, null, null)     = null
1882      * StringUtils.firstNonBlank(null, "", " ")        = null
1883      * StringUtils.firstNonBlank("abc")                = "abc"
1884      * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1885      * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1886      * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1887      * StringUtils.firstNonBlank()                     = null
1888      * </pre>
1889      *
1890      * @param <T>    the specific kind of CharSequence.
1891      * @param values the values to test, may be {@code null} or empty.
1892      * @return the first value from {@code values} which is not blank, or {@code null} if there are no non-blank values.
1893      * @since 3.8
1894      */
1895     @SafeVarargs
1896     public static <T extends CharSequence> T firstNonBlank(final T... values) {
1897         if (values != null) {
1898             for (final T val : values) {
1899                 if (isNotBlank(val)) {
1900                     return val;
1901                 }
1902             }
1903         }
1904         return null;
1905     }
1906 
1907     /**
1908      * Returns the first value in the array which is not empty.
1909      *
1910      * <p>
1911      * If all values are empty or the array is {@code null} or empty then {@code null} is returned.
1912      * </p>
1913      *
1914      * <pre>
1915      * StringUtils.firstNonEmpty(null, null, null)   = null
1916      * StringUtils.firstNonEmpty(null, null, "")     = null
1917      * StringUtils.firstNonEmpty(null, "", " ")      = " "
1918      * StringUtils.firstNonEmpty("abc")              = "abc"
1919      * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1920      * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1921      * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1922      * StringUtils.firstNonEmpty()                   = null
1923      * </pre>
1924      *
1925      * @param <T>    the specific kind of CharSequence.
1926      * @param values the values to test, may be {@code null} or empty.
1927      * @return the first value from {@code values} which is not empty, or {@code null} if there are no non-empty values.
1928      * @since 3.8
1929      */
1930     @SafeVarargs
1931     public static <T extends CharSequence> T firstNonEmpty(final T... values) {
1932         if (values != null) {
1933             for (final T val : values) {
1934                 if (isNotEmpty(val)) {
1935                     return val;
1936                 }
1937             }
1938         }
1939         return null;
1940     }
1941 
1942     /**
1943      * Calls {@link String#getBytes(Charset)} in a null-safe manner.
1944      *
1945      * @param string input string.
1946      * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
1947      * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
1948      * @see String#getBytes(Charset)
1949      * @since 3.10
1950      */
1951     public static byte[] getBytes(final String string, final Charset charset) {
1952         return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
1953     }
1954 
1955     /**
1956      * Calls {@link String#getBytes(String)} in a null-safe manner.
1957      *
1958      * @param string input string.
1959      * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
1960      * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
1961      * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
1962      * @see String#getBytes(String)
1963      * @since 3.10
1964      */
1965     public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
1966         return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
1967     }
1968 
1969     /**
1970      * Compares all Strings in an array and returns the initial sequence of characters that is common to all of them.
1971      *
1972      * <p>
1973      * For example, {@code getCommonPrefix("i am a machine", "i am a robot") -&gt; "i am a "}
1974      * </p>
1975      *
1976      * <pre>
1977      * StringUtils.getCommonPrefix(null)                             = ""
1978      * StringUtils.getCommonPrefix(new String[] {})                  = ""
1979      * StringUtils.getCommonPrefix(new String[] {"abc"})             = "abc"
1980      * StringUtils.getCommonPrefix(new String[] {null, null})        = ""
1981      * StringUtils.getCommonPrefix(new String[] {"", ""})            = ""
1982      * StringUtils.getCommonPrefix(new String[] {"", null})          = ""
1983      * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
1984      * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
1985      * StringUtils.getCommonPrefix(new String[] {"", "abc"})         = ""
1986      * StringUtils.getCommonPrefix(new String[] {"abc", ""})         = ""
1987      * StringUtils.getCommonPrefix(new String[] {"abc", "abc"})      = "abc"
1988      * StringUtils.getCommonPrefix(new String[] {"abc", "a"})        = "a"
1989      * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"})     = "ab"
1990      * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"})  = "ab"
1991      * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"})    = ""
1992      * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"})    = ""
1993      * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
1994      * </pre>
1995      *
1996      * @param strs array of String objects, entries may be null.
1997      * @return the initial sequence of characters that are common to all Strings in the array; empty String if the array is null, the elements are all null or
1998      *         if there is no common prefix.
1999      * @since 2.4
2000      */
2001     public static String getCommonPrefix(final String... strs) {
2002         if (ArrayUtils.isEmpty(strs)) {
2003             return EMPTY;
2004         }
2005         final int smallestIndexOfDiff = indexOfDifference(strs);
2006         if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2007             // all strings were identical
2008             if (strs[0] == null) {
2009                 return EMPTY;
2010             }
2011             return strs[0];
2012         }
2013         if (smallestIndexOfDiff == 0) {
2014             // there were no common initial characters
2015             return EMPTY;
2016         }
2017         // we found a common initial character sequence
2018         return strs[0].substring(0, smallestIndexOfDiff);
2019     }
2020 
2021     /**
2022      * Checks if a String {@code str} contains Unicode digits, if yes then concatenate all the digits in {@code str} and return it as a String.
2023      *
2024      * <p>
2025      * An empty ("") String will be returned if no digits found in {@code str}.
2026      * </p>
2027      *
2028      * <pre>
2029      * StringUtils.getDigits(null)                 = null
2030      * StringUtils.getDigits("")                   = ""
2031      * StringUtils.getDigits("abc")                = ""
2032      * StringUtils.getDigits("1000$")              = "1000"
2033      * StringUtils.getDigits("1123~45")            = "112345"
2034      * StringUtils.getDigits("(541) 754-3010")     = "5417543010"
2035      * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2036      * </pre>
2037      *
2038      * @param str the String to extract digits from, may be null.
2039      * @return String with only digits, or an empty ("") String if no digits found, or {@code null} String if {@code str} is null.
2040      * @since 3.6
2041      */
2042     public static String getDigits(final String str) {
2043         if (isEmpty(str)) {
2044             return str;
2045         }
2046         final int sz = str.length();
2047         final StringBuilder strDigits = new StringBuilder(sz);
2048         for (int i = 0; i < sz; i++) {
2049             final char tempChar = str.charAt(i);
2050             if (Character.isDigit(tempChar)) {
2051                 strDigits.append(tempChar);
2052             }
2053         }
2054         return strDigits.toString();
2055     }
2056 
2057     /**
2058      * Gets the Fuzzy Distance which indicates the similarity score between two Strings.
2059      *
2060      * <p>
2061      * This string matching algorithm is similar to the algorithms of editors such as Sublime Text, TextMate, Atom and others. One point is given for every
2062      * matched character. Subsequent matches yield two bonus points. A higher score indicates a higher similarity.
2063      * </p>
2064      *
2065      * <pre>
2066      * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2067      * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2068      * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2069      * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2070      * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2071      * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2072      * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2073      * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2074      * </pre>
2075      *
2076      * @param term   a full term that should be matched against, must not be null.
2077      * @param query  the query that will be matched against a term, must not be null.
2078      * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize both Strings to lower case.
2079      * @return result score.
2080      * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}.
2081      * @since 3.4
2082      * @deprecated As of 3.6, use Apache Commons Text
2083      *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2084      *             FuzzyScore</a> instead
2085      */
2086     @Deprecated
2087     public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2088         if (term == null || query == null) {
2089             throw new IllegalArgumentException("Strings must not be null");
2090         }
2091         if (locale == null) {
2092             throw new IllegalArgumentException("Locale must not be null");
2093         }
2094         // fuzzy logic is case-insensitive. We normalize the Strings to lower
2095         // case right from the start. Turning characters to lower case
2096         // via Character.toLowerCase(char) is unfortunately insufficient
2097         // as it does not accept a locale.
2098         final String termLowerCase = term.toString().toLowerCase(locale);
2099         final String queryLowerCase = query.toString().toLowerCase(locale);
2100         // the resulting score
2101         int score = 0;
2102         // the position in the term which will be scanned next for potential
2103         // query character matches
2104         int termIndex = 0;
2105         // index of the previously matched character in the term
2106         int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2107         for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2108             final char queryChar = queryLowerCase.charAt(queryIndex);
2109             boolean termCharacterMatchFound = false;
2110             for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2111                 final char termChar = termLowerCase.charAt(termIndex);
2112                 if (queryChar == termChar) {
2113                     // simple character matches result in one point
2114                     score++;
2115                     // subsequent character matches further improve
2116                     // the score.
2117                     if (previousMatchingCharacterIndex + 1 == termIndex) {
2118                         score += 2;
2119                     }
2120                     previousMatchingCharacterIndex = termIndex;
2121                     // we can leave the nested loop. Every character in the
2122                     // query can match at most one character in the term.
2123                     termCharacterMatchFound = true;
2124                 }
2125             }
2126         }
2127         return score;
2128     }
2129 
2130     /**
2131      * Returns either the passed in CharSequence, or if the CharSequence is {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or
2132      * {@code null}), the value supplied by {@code defaultStrSupplier}.
2133      *
2134      * <p>
2135      * Whitespace is defined by {@link Character#isWhitespace(char)}.
2136      * </p>
2137      *
2138      * <p>
2139      * Caller responsible for thread-safety and exception handling of default value supplier
2140      * </p>
2141      *
2142      * <pre>
2143      * {@code
2144      * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2145      * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2146      * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2147      * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2148      * StringUtils.getIfBlank("", () -> null)       = null
2149      * StringUtils.getIfBlank("", null)             = null
2150      * }</pre>
2151      *
2152      * @param <T>             the specific kind of CharSequence.
2153      * @param str             the CharSequence to check, may be null.
2154      * @param defaultSupplier the supplier of default CharSequence to return if the input is {@link #isBlank(CharSequence) blank} (whitespaces, empty
2155      *                        ({@code ""}) or {@code null}); may be null.
2156      * @return the passed in CharSequence, or the default
2157      * @see StringUtils#defaultString(String, String)
2158      * @see #isBlank(CharSequence)
2159      * @since 3.10
2160      */
2161     public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2162         return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2163     }
2164 
2165     /**
2166      * Returns either the passed in CharSequence, or if the CharSequence is empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2167      *
2168      * <p>
2169      * Caller responsible for thread-safety and exception handling of default value supplier
2170      * </p>
2171      *
2172      * <pre>
2173      * {@code
2174      * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2175      * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2176      * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2177      * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2178      * StringUtils.getIfEmpty("", () -> null)        = null
2179      * StringUtils.getIfEmpty("", null)              = null
2180      * }
2181      * </pre>
2182      *
2183      * @param <T>             the specific kind of CharSequence.
2184      * @param str             the CharSequence to check, may be null.
2185      * @param defaultSupplier the supplier of default CharSequence to return if the input is empty ("") or {@code null}, may be null.
2186      * @return the passed in CharSequence, or the default.
2187      * @see StringUtils#defaultString(String, String)
2188      * @since 3.10
2189      */
2190     public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2191         return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2192     }
2193 
2194     /**
2195      * Gets the Jaro Winkler Distance which indicates the similarity score between two Strings.
2196      *
2197      * <p>
2198      * The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. Winkler increased this measure for
2199      * matching initial characters.
2200      * </p>
2201      *
2202      * <p>
2203      * This implementation is based on the Jaro Winkler similarity algorithm from
2204      * <a href="https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
2205      * </p>
2206      *
2207      * <pre>
2208      * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2209      * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2210      * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2211      * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2212      * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2213      * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2214      * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2215      * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2216      * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2217      * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2218      * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2219      * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2220      * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2221      * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2222      * </pre>
2223      *
2224      * @param first  the first String, must not be null.
2225      * @param second the second String, must not be null.
2226      * @return result distance.
2227      * @throws IllegalArgumentException if either String input {@code null}.
2228      * @since 3.3
2229      * @deprecated As of 3.6, use Apache Commons Text
2230      *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2231      *             JaroWinklerDistance</a> instead
2232      */
2233     @Deprecated
2234     public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2235         final double DEFAULT_SCALING_FACTOR = 0.1;
2236 
2237         if (first == null || second == null) {
2238             throw new IllegalArgumentException("Strings must not be null");
2239         }
2240 
2241         final int[] mtp = matches(first, second);
2242         final double m = mtp[0];
2243         if (m == 0) {
2244             return 0D;
2245         }
2246         final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2247         final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2248         return Math.round(jw * 100.0D) / 100.0D;
2249     }
2250 
2251     /**
2252      * Gets the Levenshtein distance between two Strings.
2253      *
2254      * <p>
2255      * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2256      * substitution).
2257      * </p>
2258      *
2259      * <p>
2260      * The implementation uses a single-dimensional array of length s.length() + 1. See
2261      * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2262      * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.
2263      * </p>
2264      *
2265      * <pre>
2266      * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2267      * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2268      * StringUtils.getLevenshteinDistance("", "")              = 0
2269      * StringUtils.getLevenshteinDistance("", "a")             = 1
2270      * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2271      * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2272      * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2273      * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2274      * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2275      * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2276      * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2277      * </pre>
2278      *
2279      * @param s the first String, must not be null.
2280      * @param t the second String, must not be null.
2281      * @return result distance.
2282      * @throws IllegalArgumentException if either String input {@code null}.
2283      * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to getLevenshteinDistance(CharSequence, CharSequence)
2284      * @deprecated As of 3.6, use Apache Commons Text
2285      *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2286      *             LevenshteinDistance</a> instead
2287      */
2288     @Deprecated
2289     public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2290         if (s == null || t == null) {
2291             throw new IllegalArgumentException("Strings must not be null");
2292         }
2293 
2294         int n = s.length();
2295         int m = t.length();
2296 
2297         if (n == 0) {
2298             return m;
2299         }
2300         if (m == 0) {
2301             return n;
2302         }
2303 
2304         if (n > m) {
2305             // swap the input strings to consume less memory
2306             final CharSequence tmp = s;
2307             s = t;
2308             t = tmp;
2309             n = m;
2310             m = t.length();
2311         }
2312 
2313         final int[] p = new int[n + 1];
2314         // indexes into strings s and t
2315         int i; // iterates through s
2316         int j; // iterates through t
2317         int upperleft;
2318         int upper;
2319 
2320         char jOfT; // jth character of t
2321         int cost;
2322 
2323         for (i = 0; i <= n; i++) {
2324             p[i] = i;
2325         }
2326 
2327         for (j = 1; j <= m; j++) {
2328             upperleft = p[0];
2329             jOfT = t.charAt(j - 1);
2330             p[0] = j;
2331 
2332             for (i = 1; i <= n; i++) {
2333                 upper = p[i];
2334                 cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2335                 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2336                 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2337                 upperleft = upper;
2338             }
2339         }
2340 
2341         return p[n];
2342     }
2343 
2344     /**
2345      * Gets the Levenshtein distance between two Strings if it's less than or equal to a given threshold.
2346      *
2347      * <p>
2348      * This is the number of changes needed to change one String into another, where each change is a single character modification (deletion, insertion or
2349      * substitution).
2350      * </p>
2351      *
2352      * <p>
2353      * This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield and Chas Emerick's implementation of the Levenshtein distance
2354      * algorithm from <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a>
2355      * </p>
2356      *
2357      * <pre>
2358      * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2359      * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2360      * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2361      * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2362      * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2363      * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2364      * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2365      * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2366      * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2367      * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2368      * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2369      * </pre>
2370      *
2371      * @param s         the first String, must not be null.
2372      * @param t         the second String, must not be null.
2373      * @param threshold the target threshold, must not be negative.
2374      * @return result distance, or {@code -1} if the distance would be greater than the threshold.
2375      * @throws IllegalArgumentException if either String input {@code null} or negative threshold.
2376      * @deprecated As of 3.6, use Apache Commons Text
2377      *             <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2378      *             LevenshteinDistance</a> instead
2379      */
2380     @Deprecated
2381     public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2382         if (s == null || t == null) {
2383             throw new IllegalArgumentException("Strings must not be null");
2384         }
2385         if (threshold < 0) {
2386             throw new IllegalArgumentException("Threshold must not be negative");
2387         }
2388 
2389         /*
2390         This implementation only computes the distance if it's less than or equal to the
2391         threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2392         distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2393         computing a diagonal stripe of width 2k + 1 of the cost table.
2394         It is also possible to use this to compute the unbounded Levenshtein distance by starting
2395         the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2396         d is the distance.
2397 
2398         One subtlety comes from needing to ignore entries on the border of our stripe
2399         eg.
2400         p[] = |#|#|#|*
2401         d[] =  *|#|#|#|
2402         We must ignore the entry to the left of the leftmost member
2403         We must ignore the entry above the rightmost member
2404 
2405         Another subtlety comes from our stripe running off the matrix if the strings aren't
2406         of the same size.  Since string s is always swapped to be the shorter of the two,
2407         the stripe will always run off to the upper right instead of the lower left of the matrix.
2408 
2409         As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2410         In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2411 
2412            1 2 3 4 5
2413         1 |#|#| | | |
2414         2 |#|#|#| | |
2415         3 | |#|#|#| |
2416         4 | | |#|#|#|
2417         5 | | | |#|#|
2418         6 | | | | |#|
2419         7 | | | | | |
2420 
2421         Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2422         into one of length 7 in edit distance of 1.
2423 
2424         Additionally, this implementation decreases memory usage by using two
2425         single-dimensional arrays and swapping them back and forth instead of allocating
2426         an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2427         when it's detected that the stripe has run off the matrix and initially filling the arrays with
2428         large values so that entries we don't compute are ignored.
2429 
2430         See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2431          */
2432 
2433         int n = s.length(); // length of s
2434         int m = t.length(); // length of t
2435 
2436         // if one string is empty, the edit distance is necessarily the length of the other
2437         if (n == 0) {
2438             return m <= threshold ? m : -1;
2439         }
2440         if (m == 0) {
2441             return n <= threshold ? n : -1;
2442         }
2443         if (Math.abs(n - m) > threshold) {
2444             // no need to calculate the distance if the length difference is greater than the threshold
2445             return -1;
2446         }
2447 
2448         if (n > m) {
2449             // swap the two strings to consume less memory
2450             final CharSequence tmp = s;
2451             s = t;
2452             t = tmp;
2453             n = m;
2454             m = t.length();
2455         }
2456 
2457         int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2458         int[] d = new int[n + 1]; // cost array, horizontally
2459         int[] tmp; // placeholder to assist in swapping p and d
2460 
2461         // fill in starting table values
2462         final int boundary = Math.min(n, threshold) + 1;
2463         for (int i = 0; i < boundary; i++) {
2464             p[i] = i;
2465         }
2466         // these fills ensure that the value above the rightmost entry of our
2467         // stripe will be ignored in following loop iterations
2468         Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2469         Arrays.fill(d, Integer.MAX_VALUE);
2470 
2471         // iterates through t
2472         for (int j = 1; j <= m; j++) {
2473             final char jOfT = t.charAt(j - 1); // jth character of t
2474             d[0] = j;
2475 
2476             // compute stripe indices, constrain to array size
2477             final int min = Math.max(1, j - threshold);
2478             final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2479 
2480             // the stripe may lead off of the table if s and t are of different sizes
2481             if (min > max) {
2482                 return -1;
2483             }
2484 
2485             // ignore entry left of leftmost
2486             if (min > 1) {
2487                 d[min - 1] = Integer.MAX_VALUE;
2488             }
2489 
2490             // iterates through [min, max] in s
2491             for (int i = min; i <= max; i++) {
2492                 if (s.charAt(i - 1) == jOfT) {
2493                     // diagonally left and up
2494                     d[i] = p[i - 1];
2495                 } else {
2496                     // 1 + minimum of cell to the left, to the top, diagonally left and up
2497                     d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2498                 }
2499             }
2500 
2501             // copy current distance counts to 'previous row' distance counts
2502             tmp = p;
2503             p = d;
2504             d = tmp;
2505         }
2506 
2507         // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2508         // distance
2509         if (p[n] <= threshold) {
2510             return p[n];
2511         }
2512         return -1;
2513     }
2514 
2515     /**
2516      * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2517      *
2518      * <p>
2519      * A {@code null} CharSequence will return {@code -1}.
2520      * </p>
2521      *
2522      * <pre>
2523      * StringUtils.indexOf(null, *)          = -1
2524      * StringUtils.indexOf(*, null)          = -1
2525      * StringUtils.indexOf("", "")           = 0
2526      * StringUtils.indexOf("", *)            = -1 (except when * = "")
2527      * StringUtils.indexOf("aabaabaa", "a")  = 0
2528      * StringUtils.indexOf("aabaabaa", "b")  = 2
2529      * StringUtils.indexOf("aabaabaa", "ab") = 1
2530      * StringUtils.indexOf("aabaabaa", "")   = 0
2531      * </pre>
2532      *
2533      * @param seq       the CharSequence to check, may be null.
2534      * @param searchSeq the CharSequence to find, may be null.
2535      * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
2536      * @since 2.0
2537      * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2538      * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CS.indexOf(CharSequence, CharSequence)}
2539      */
2540     @Deprecated
2541     public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2542         return Strings.CS.indexOf(seq, searchSeq);
2543     }
2544 
2545     /**
2546      * Finds the first index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String, int)} if possible.
2547      *
2548      * <p>
2549      * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
2550      * start position greater than the string length only matches an empty search CharSequence.
2551      * </p>
2552      *
2553      * <pre>
2554      * StringUtils.indexOf(null, *, *)          = -1
2555      * StringUtils.indexOf(*, null, *)          = -1
2556      * StringUtils.indexOf("", "", 0)           = 0
2557      * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2558      * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2559      * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2560      * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2561      * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2562      * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2563      * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2564      * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2565      * StringUtils.indexOf("abc", "", 9)        = 3
2566      * </pre>
2567      *
2568      * @param seq       the CharSequence to check, may be null.
2569      * @param searchSeq the CharSequence to find, may be null.
2570      * @param startPos  the start position, negative treated as zero.
2571      * @return the first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
2572      * @since 2.0
2573      * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2574      * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CS.indexOf(CharSequence, CharSequence, int)}
2575      */
2576     @Deprecated
2577     public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2578         return Strings.CS.indexOf(seq, searchSeq, startPos);
2579     }
2580 
2581     /**
2582      * Returns the index within {@code seq} of the first occurrence of the specified character. If a character with value {@code searchChar} occurs in the
2583      * character sequence represented by {@code seq} {@link CharSequence} object, then the index (in Unicode code units) of the first such occurrence is
2584      * returned. For values of {@code searchChar} in the range from 0 to 0xFFFF (inclusive), this is the smallest value <em>k</em> such that:
2585      *
2586      * <pre>
2587      * this.charAt(<em>k</em>) == searchChar
2588      * </pre>
2589      *
2590      * <p>
2591      * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2592      * </p>
2593      *
2594      * <pre>
2595      * this.codePointAt(<em>k</em>) == searchChar
2596      * </pre>
2597      *
2598      * <p>
2599      * is true. In either case, if no such character occurs in {@code seq}, then {@code INDEX_NOT_FOUND (-1)} is returned.
2600      * </p>
2601      *
2602      * <p>
2603      * Furthermore, a {@code null} or empty ("") CharSequence will return {@code INDEX_NOT_FOUND (-1)}.
2604      * </p>
2605      *
2606      * <pre>
2607      * StringUtils.indexOf(null, *)         = -1
2608      * StringUtils.indexOf("", *)           = -1
2609      * StringUtils.indexOf("aabaabaa", 'a') = 0
2610      * StringUtils.indexOf("aabaabaa", 'b') = 2
2611      * StringUtils.indexOf("aaaaaaaa", 'Z') = -1
2612      * </pre>
2613      *
2614      * @param seq        the CharSequence to check, may be null.
2615      * @param searchChar the character to find.
2616      * @return the first index of the search character, -1 if no match or {@code null} string input.
2617      * @since 2.0
2618      * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2619      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2620      */
2621     public static int indexOf(final CharSequence seq, final int searchChar) {
2622         if (isEmpty(seq)) {
2623             return INDEX_NOT_FOUND;
2624         }
2625         return CharSequenceUtils.indexOf(seq, searchChar, 0);
2626     }
2627 
2628     /**
2629      * Returns the index within {@code seq} of the first occurrence of the specified character, starting the search at the specified index.
2630      * <p>
2631      * If a character with value {@code searchChar} occurs in the character sequence represented by the {@code seq} {@link CharSequence} object at an index no
2632      * smaller than {@code startPos}, then the index of the first such occurrence is returned. For values of {@code searchChar} in the range from 0 to 0xFFFF
2633      * (inclusive), this is the smallest value <em>k</em> such that:
2634      * </p>
2635      *
2636      * <pre>
2637      * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2638      * </pre>
2639      *
2640      * <p>
2641      * is true. For other values of {@code searchChar}, it is the smallest value <em>k</em> such that:
2642      * </p>
2643      *
2644      * <pre>
2645      * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &gt;= startPos)
2646      * </pre>
2647      *
2648      * <p>
2649      * is true. In either case, if no such character occurs in {@code seq} at or after position {@code startPos}, then {@code -1} is returned.
2650      * </p>
2651      *
2652      * <p>
2653      * There is no restriction on the value of {@code startPos}. If it is negative, it has the same effect as if it were zero: this entire string may be
2654      * searched. If it is greater than the length of this string, it has the same effect as if it were equal to the length of this string:
2655      * {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a {@code null} or empty ("") CharSequence will return {@code (INDEX_NOT_FOUND) -1}.
2656      * </p>
2657      * <p>
2658      * All indices are specified in {@code char} values (Unicode code units).
2659      *
2660      * <pre>
2661      * StringUtils.indexOf(null, *, *)          = -1
2662      * StringUtils.indexOf("", *, *)            = -1
2663      * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2664      * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2665      * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2666      * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2667      * </pre>
2668      *
2669      * @param seq        the CharSequence to check, may be null.
2670      * @param searchChar the character to find.
2671      * @param startPos   the start position, negative treated as zero.
2672      * @return the first index of the search character (always &ge; startPos), -1 if no match or {@code null} string input.
2673      * @since 2.0
2674      * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2675      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2676      */
2677     public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2678         if (isEmpty(seq)) {
2679             return INDEX_NOT_FOUND;
2680         }
2681         return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2682     }
2683 
2684     /**
2685      * Search a CharSequence to find the first index of any character in the given set of characters.
2686      *
2687      * <p>
2688      * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2689      * </p>
2690      *
2691      * <pre>
2692      * StringUtils.indexOfAny(null, *)                  = -1
2693      * StringUtils.indexOfAny("", *)                    = -1
2694      * StringUtils.indexOfAny(*, null)                  = -1
2695      * StringUtils.indexOfAny(*, [])                    = -1
2696      * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2697      * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2698      * StringUtils.indexOfAny("aba", ['z'])             = -1
2699      * </pre>
2700      *
2701      * @param cs          the CharSequence to check, may be null.
2702      * @param searchChars the chars to search for, may be null.
2703      * @return the index of any of the chars, -1 if no match or null input.
2704      * @since 2.0
2705      * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2706      */
2707     public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2708         return indexOfAny(cs, 0, searchChars);
2709     }
2710 
2711     /**
2712      * Find the first index of any of a set of potential substrings.
2713      *
2714      * <p>
2715      * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}. A {@code null} search array entry
2716      * will be ignored, but a search array containing "" will return {@code 0} if {@code str} is not null. This method uses {@link String#indexOf(String)} if
2717      * possible.
2718      * </p>
2719      *
2720      * <pre>
2721      * StringUtils.indexOfAny(null, *)                      = -1
2722      * StringUtils.indexOfAny(*, null)                      = -1
2723      * StringUtils.indexOfAny(*, [])                        = -1
2724      * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2725      * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2726      * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2727      * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2728      * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2729      * StringUtils.indexOfAny("", [""])                     = 0
2730      * StringUtils.indexOfAny("", ["a"])                    = -1
2731      * </pre>
2732      *
2733      * @param str        the CharSequence to check, may be null.
2734      * @param searchStrs the CharSequences to search for, may be null.
2735      * @return the first index of any of the searchStrs in str, -1 if no match.
2736      * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2737      */
2738     public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2739         if (str == null || searchStrs == null) {
2740             return INDEX_NOT_FOUND;
2741         }
2742         // String's can't have a MAX_VALUEth index.
2743         int ret = Integer.MAX_VALUE;
2744         int tmp;
2745         for (final CharSequence search : searchStrs) {
2746             if (search == null) {
2747                 continue;
2748             }
2749             tmp = CharSequenceUtils.indexOf(str, search, 0);
2750             if (tmp == INDEX_NOT_FOUND) {
2751                 continue;
2752             }
2753             if (tmp < ret) {
2754                 ret = tmp;
2755             }
2756         }
2757         return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2758     }
2759 
2760     /**
2761      * Search a CharSequence to find the first index of any character in the given set of characters.
2762      *
2763      * <p>
2764      * A {@code null} String will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2765      * </p>
2766      * <p>
2767      * The following is the same as {@code indexOfAny(cs, 0, searchChars)}.
2768      * </p>
2769      * <pre>
2770      * StringUtils.indexOfAny(null, 0, *)                  = -1
2771      * StringUtils.indexOfAny("", 0, *)                    = -1
2772      * StringUtils.indexOfAny(*, 0, null)                  = -1
2773      * StringUtils.indexOfAny(*, 0, [])                    = -1
2774      * StringUtils.indexOfAny("zzabyycdxx", 0, ['z', 'a']) = 0
2775      * StringUtils.indexOfAny("zzabyycdxx", 0, ['b', 'y']) = 3
2776      * StringUtils.indexOfAny("aba", 0, ['z'])             = -1
2777      * </pre>
2778      *
2779      * @param cs          the CharSequence to check, may be null.
2780      * @param csStart Start searching the input {@code cs} at this index.
2781      * @param searchChars the chars to search for, may be null.
2782      * @return the index of any of the chars, -1 if no match or null input.
2783      * @since 2.0
2784      * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2785      */
2786     public static int indexOfAny(final CharSequence cs, final int csStart, final char... searchChars) {
2787         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2788             return INDEX_NOT_FOUND;
2789         }
2790         final int csLen = cs.length();
2791         final int csLast = csLen - 1;
2792         final int searchLen = searchChars.length;
2793         final int searchLast = searchLen - 1;
2794         for (int i = csStart; i < csLen; i++) {
2795             final char ch = cs.charAt(i);
2796             for (int j = 0; j < searchLen; j++) {
2797                 if (searchChars[j] == ch) {
2798                     // ch is a supplementary character
2799                     if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch) || searchChars[j + 1] == cs.charAt(i + 1)) {
2800                         return i;
2801                     }
2802                 }
2803             }
2804         }
2805         return INDEX_NOT_FOUND;
2806     }
2807 
2808     /**
2809      * Search a CharSequence to find the first index of any character in the given set of characters.
2810      *
2811      * <p>
2812      * A {@code null} String will return {@code -1}. A {@code null} search string will return {@code -1}.
2813      * </p>
2814      *
2815      * <pre>
2816      * StringUtils.indexOfAny(null, *)            = -1
2817      * StringUtils.indexOfAny("", *)              = -1
2818      * StringUtils.indexOfAny(*, null)            = -1
2819      * StringUtils.indexOfAny(*, "")              = -1
2820      * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2821      * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2822      * StringUtils.indexOfAny("aba", "z")         = -1
2823      * </pre>
2824      *
2825      * @param cs          the CharSequence to check, may be null.
2826      * @param searchChars the chars to search for, may be null.
2827      * @return the index of any of the chars, -1 if no match or null input.
2828      * @since 2.0
2829      * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2830      */
2831     public static int indexOfAny(final CharSequence cs, final String searchChars) {
2832         if (isEmpty(cs) || isEmpty(searchChars)) {
2833             return INDEX_NOT_FOUND;
2834         }
2835         return indexOfAny(cs, searchChars.toCharArray());
2836     }
2837 
2838     /**
2839      * Searches a CharSequence to find the first index of any character not in the given set of characters, i.e., find index i of first char in cs such that
2840      * (cs.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2841      *
2842      * <p>
2843      * A {@code null} CharSequence will return {@code -1}. A {@code null} or zero length search array will return {@code -1}.
2844      * </p>
2845      *
2846      * <pre>
2847      * StringUtils.indexOfAnyBut(null, *)                              = -1
2848      * StringUtils.indexOfAnyBut("", *)                                = -1
2849      * StringUtils.indexOfAnyBut(*, null)                              = -1
2850      * StringUtils.indexOfAnyBut(*, [])                                = -1
2851      * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2852      * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2853      * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2854      * </pre>
2855      *
2856      * @param cs          the CharSequence to check, may be null.
2857      * @param searchChars the chars to search for, may be null.
2858      * @return the index of any of the chars, -1 if no match or null input.
2859      * @since 2.0
2860      * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2861      */
2862     public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2863         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2864             return INDEX_NOT_FOUND;
2865         }
2866         return indexOfAnyBut(cs, CharBuffer.wrap(searchChars));
2867     }
2868 
2869     /**
2870      * Search a CharSequence to find the first index of any character not in the given set of characters, i.e., find index i of first char in seq such that
2871      * (seq.codePointAt(i) ∉ { x ∈ codepoints(searchChars) })
2872      *
2873      * <p>
2874      * A {@code null} CharSequence will return {@code -1}. A {@code null} or empty search string will return {@code -1}.
2875      * </p>
2876      *
2877      * <pre>
2878      * StringUtils.indexOfAnyBut(null, *)            = -1
2879      * StringUtils.indexOfAnyBut("", *)              = -1
2880      * StringUtils.indexOfAnyBut(*, null)            = -1
2881      * StringUtils.indexOfAnyBut(*, "")              = -1
2882      * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2883      * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2884      * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2885      * </pre>
2886      *
2887      * @param seq         the CharSequence to check, may be null.
2888      * @param searchChars the chars to search for, may be null.
2889      * @return the index of any of the chars, -1 if no match or null input.
2890      * @since 2.0
2891      * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2892      */
2893     public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2894         if (isEmpty(seq) || isEmpty(searchChars)) {
2895             return INDEX_NOT_FOUND;
2896         }
2897         final Set<Integer> searchSetCodePoints = searchChars.codePoints()
2898                 .boxed().collect(Collectors.toSet());
2899         // advance character index from one interpreted codepoint to the next
2900         for (int curSeqCharIdx = 0; curSeqCharIdx < seq.length();) {
2901             final int curSeqCodePoint = Character.codePointAt(seq, curSeqCharIdx);
2902             if (!searchSetCodePoints.contains(curSeqCodePoint)) {
2903                 return curSeqCharIdx;
2904             }
2905             curSeqCharIdx += Character.charCount(curSeqCodePoint); // skip indices to paired low-surrogates
2906         }
2907         return INDEX_NOT_FOUND;
2908     }
2909 
2910     /**
2911      * Compares all CharSequences in an array and returns the index at which the CharSequences begin to differ.
2912      *
2913      * <p>
2914      * For example, {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}
2915      * </p>
2916      *
2917      * <pre>
2918      * StringUtils.indexOfDifference(null)                             = -1
2919      * StringUtils.indexOfDifference(new String[] {})                  = -1
2920      * StringUtils.indexOfDifference(new String[] {"abc"})             = -1
2921      * StringUtils.indexOfDifference(new String[] {null, null})        = -1
2922      * StringUtils.indexOfDifference(new String[] {"", ""})            = -1
2923      * StringUtils.indexOfDifference(new String[] {"", null})          = 0
2924      * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
2925      * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
2926      * StringUtils.indexOfDifference(new String[] {"", "abc"})         = 0
2927      * StringUtils.indexOfDifference(new String[] {"abc", ""})         = 0
2928      * StringUtils.indexOfDifference(new String[] {"abc", "abc"})      = -1
2929      * StringUtils.indexOfDifference(new String[] {"abc", "a"})        = 1
2930      * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"})     = 2
2931      * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"})  = 2
2932      * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"})    = 0
2933      * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"})    = 0
2934      * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
2935      * </pre>
2936      *
2937      * @param css array of CharSequences, entries may be null.
2938      * @return the index where the strings begin to differ; -1 if they are all equal.
2939      * @since 2.4
2940      * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
2941      */
2942     public static int indexOfDifference(final CharSequence... css) {
2943         if (ArrayUtils.getLength(css) <= 1) {
2944             return INDEX_NOT_FOUND;
2945         }
2946         boolean anyStringNull = false;
2947         boolean allStringsNull = true;
2948         final int arrayLen = css.length;
2949         int shortestStrLen = Integer.MAX_VALUE;
2950         int longestStrLen = 0;
2951         // find the min and max string lengths; this avoids checking to make
2952         // sure we are not exceeding the length of the string each time through
2953         // the bottom loop.
2954         for (final CharSequence cs : css) {
2955             if (cs == null) {
2956                 anyStringNull = true;
2957                 shortestStrLen = 0;
2958             } else {
2959                 allStringsNull = false;
2960                 shortestStrLen = Math.min(cs.length(), shortestStrLen);
2961                 longestStrLen = Math.max(cs.length(), longestStrLen);
2962             }
2963         }
2964         // handle lists containing all nulls or all empty strings
2965         if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
2966             return INDEX_NOT_FOUND;
2967         }
2968         // handle lists containing some nulls or some empty strings
2969         if (shortestStrLen == 0) {
2970             return 0;
2971         }
2972         // find the position with the first difference across all strings
2973         int firstDiff = -1;
2974         for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
2975             final char comparisonChar = css[0].charAt(stringPos);
2976             for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
2977                 if (css[arrayPos].charAt(stringPos) != comparisonChar) {
2978                     firstDiff = stringPos;
2979                     break;
2980                 }
2981             }
2982             if (firstDiff != -1) {
2983                 break;
2984             }
2985         }
2986         if (firstDiff == -1 && shortestStrLen != longestStrLen) {
2987             // we compared all of the characters up to the length of the
2988             // shortest string and didn't find a match, but the string lengths
2989             // vary, so return the length of the shortest string.
2990             return shortestStrLen;
2991         }
2992         return firstDiff;
2993     }
2994 
2995     /**
2996      * Compares two CharSequences, and returns the index at which the CharSequences begin to differ.
2997      *
2998      * <p>
2999      * For example, {@code indexOfDifference("i am a machine", "i am a robot") -> 7}
3000      * </p>
3001      *
3002      * <pre>
3003      * StringUtils.indexOfDifference(null, null)       = -1
3004      * StringUtils.indexOfDifference("", "")           = -1
3005      * StringUtils.indexOfDifference("", "abc")        = 0
3006      * StringUtils.indexOfDifference("abc", "")        = 0
3007      * StringUtils.indexOfDifference("abc", "abc")     = -1
3008      * StringUtils.indexOfDifference("ab", "abxyz")    = 2
3009      * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3010      * StringUtils.indexOfDifference("abcde", "xyz")   = 0
3011      * </pre>
3012      *
3013      * @param cs1 the first CharSequence, may be null.
3014      * @param cs2 the second CharSequence, may be null.
3015      * @return the index where cs1 and cs2 begin to differ; -1 if they are equal.
3016      * @since 2.0
3017      * @since 3.0 Changed signature from indexOfDifference(String, String) to indexOfDifference(CharSequence, CharSequence)
3018      */
3019     public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3020         if (cs1 == cs2) {
3021             return INDEX_NOT_FOUND;
3022         }
3023         if (cs1 == null || cs2 == null) {
3024             return 0;
3025         }
3026         int i;
3027         for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3028             if (cs1.charAt(i) != cs2.charAt(i)) {
3029                 break;
3030             }
3031         }
3032         if (i < cs2.length() || i < cs1.length()) {
3033             return i;
3034         }
3035         return INDEX_NOT_FOUND;
3036     }
3037 
3038     /**
3039      * Case in-sensitive find of the first index within a CharSequence.
3040      *
3041      * <p>
3042      * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3043      * start position greater than the string length only matches an empty search CharSequence.
3044      * </p>
3045      *
3046      * <pre>
3047      * StringUtils.indexOfIgnoreCase(null, *)          = -1
3048      * StringUtils.indexOfIgnoreCase(*, null)          = -1
3049      * StringUtils.indexOfIgnoreCase("", "")           = 0
3050      * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3051      * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3052      * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3053      * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3054      * </pre>
3055      *
3056      * @param str       the CharSequence to check, may be null.
3057      * @param searchStr the CharSequence to find, may be null.
3058      * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
3059      * @since 2.5
3060      * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3061      * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence) Strings.CI.indexOf(CharSequence, CharSequence)}
3062      */
3063     @Deprecated
3064     public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3065         return Strings.CI.indexOf(str, searchStr);
3066     }
3067 
3068     /**
3069      * Case in-sensitive find of the first index within a CharSequence from the specified position.
3070      *
3071      * <p>
3072      * A {@code null} CharSequence will return {@code -1}. A negative start position is treated as zero. An empty ("") search CharSequence always matches. A
3073      * start position greater than the string length only matches an empty search CharSequence.
3074      * </p>
3075      *
3076      * <pre>
3077      * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3078      * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3079      * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3080      * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3081      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3082      * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3083      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3084      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3085      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3086      * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3087      * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3088      * </pre>
3089      *
3090      * @param str       the CharSequence to check, may be null.
3091      * @param searchStr the CharSequence to find, may be null.
3092      * @param startPos  the start position, negative treated as zero.
3093      * @return the first index of the search CharSequence (always &ge; startPos), -1 if no match or {@code null} string input.
3094      * @since 2.5
3095      * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3096      * @deprecated Use {@link Strings#indexOf(CharSequence, CharSequence, int) Strings.CI.indexOf(CharSequence, CharSequence, int)}
3097      */
3098     @Deprecated
3099     public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
3100         return Strings.CI.indexOf(str, searchStr, startPos);
3101     }
3102 
3103     /**
3104      * Tests if all of the CharSequences are empty (""), null or whitespace only.
3105      *
3106      * <p>
3107      * Whitespace is defined by {@link Character#isWhitespace(char)}.
3108      * </p>
3109      *
3110      * <pre>
3111      * StringUtils.isAllBlank(null)             = true
3112      * StringUtils.isAllBlank(null, "foo")      = false
3113      * StringUtils.isAllBlank(null, null)       = true
3114      * StringUtils.isAllBlank("", "bar")        = false
3115      * StringUtils.isAllBlank("bob", "")        = false
3116      * StringUtils.isAllBlank("  bob  ", null)  = false
3117      * StringUtils.isAllBlank(" ", "bar")       = false
3118      * StringUtils.isAllBlank("foo", "bar")     = false
3119      * StringUtils.isAllBlank(new String[] {})  = true
3120      * </pre>
3121      *
3122      * @param css the CharSequences to check, may be null or empty.
3123      * @return {@code true} if all of the CharSequences are empty or null or whitespace only.
3124      * @since 3.6
3125      */
3126     public static boolean isAllBlank(final CharSequence... css) {
3127         if (ArrayUtils.isEmpty(css)) {
3128             return true;
3129         }
3130         for (final CharSequence cs : css) {
3131             if (isNotBlank(cs)) {
3132                return false;
3133             }
3134         }
3135         return true;
3136     }
3137 
3138     /**
3139      * Tests if all of the CharSequences are empty ("") or null.
3140      *
3141      * <pre>
3142      * StringUtils.isAllEmpty(null)             = true
3143      * StringUtils.isAllEmpty(null, "")         = true
3144      * StringUtils.isAllEmpty(new String[] {})  = true
3145      * StringUtils.isAllEmpty(null, "foo")      = false
3146      * StringUtils.isAllEmpty("", "bar")        = false
3147      * StringUtils.isAllEmpty("bob", "")        = false
3148      * StringUtils.isAllEmpty("  bob  ", null)  = false
3149      * StringUtils.isAllEmpty(" ", "bar")       = false
3150      * StringUtils.isAllEmpty("foo", "bar")     = false
3151      * </pre>
3152      *
3153      * @param css the CharSequences to check, may be null or empty.
3154      * @return {@code true} if all of the CharSequences are empty or null.
3155      * @since 3.6
3156      */
3157     public static boolean isAllEmpty(final CharSequence... css) {
3158         if (ArrayUtils.isEmpty(css)) {
3159             return true;
3160         }
3161         for (final CharSequence cs : css) {
3162             if (isNotEmpty(cs)) {
3163                 return false;
3164             }
3165         }
3166         return true;
3167     }
3168 
3169     /**
3170      * Tests if the CharSequence contains only lowercase characters.
3171      *
3172      * <p>
3173      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3174      * </p>
3175      *
3176      * <pre>
3177      * StringUtils.isAllLowerCase(null)   = false
3178      * StringUtils.isAllLowerCase("")     = false
3179      * StringUtils.isAllLowerCase("  ")   = false
3180      * StringUtils.isAllLowerCase("abc")  = true
3181      * StringUtils.isAllLowerCase("abC")  = false
3182      * StringUtils.isAllLowerCase("ab c") = false
3183      * StringUtils.isAllLowerCase("ab1c") = false
3184      * StringUtils.isAllLowerCase("ab/c") = false
3185      * </pre>
3186      *
3187      * @param cs the CharSequence to check, may be null.
3188      * @return {@code true} if only contains lowercase characters, and is non-null.
3189      * @since 2.5
3190      * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3191      */
3192     public static boolean isAllLowerCase(final CharSequence cs) {
3193         if (isEmpty(cs)) {
3194             return false;
3195         }
3196         final int sz = cs.length();
3197         for (int i = 0; i < sz; i++) {
3198             if (!Character.isLowerCase(cs.charAt(i))) {
3199                 return false;
3200             }
3201         }
3202         return true;
3203     }
3204 
3205     /**
3206      * Tests if the CharSequence contains only uppercase characters.
3207      *
3208      * <p>{@code null} will return {@code false}.
3209      * An empty String (length()=0) will return {@code false}.</p>
3210      *
3211      * <pre>
3212      * StringUtils.isAllUpperCase(null)   = false
3213      * StringUtils.isAllUpperCase("")     = false
3214      * StringUtils.isAllUpperCase("  ")   = false
3215      * StringUtils.isAllUpperCase("ABC")  = true
3216      * StringUtils.isAllUpperCase("aBC")  = false
3217      * StringUtils.isAllUpperCase("A C")  = false
3218      * StringUtils.isAllUpperCase("A1C")  = false
3219      * StringUtils.isAllUpperCase("A/C")  = false
3220      * </pre>
3221      *
3222      * @param cs the CharSequence to check, may be null.
3223      * @return {@code true} if only contains uppercase characters, and is non-null.
3224      * @since 2.5
3225      * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3226      */
3227     public static boolean isAllUpperCase(final CharSequence cs) {
3228         if (isEmpty(cs)) {
3229             return false;
3230         }
3231         final int sz = cs.length();
3232         for (int i = 0; i < sz; i++) {
3233             if (!Character.isUpperCase(cs.charAt(i))) {
3234                 return false;
3235             }
3236         }
3237         return true;
3238     }
3239 
3240     /**
3241      * Tests if the CharSequence contains only Unicode letters.
3242      *
3243      * <p>
3244      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3245      * </p>
3246      *
3247      * <pre>
3248      * StringUtils.isAlpha(null)   = false
3249      * StringUtils.isAlpha("")     = false
3250      * StringUtils.isAlpha("  ")   = false
3251      * StringUtils.isAlpha("abc")  = true
3252      * StringUtils.isAlpha("ab2c") = false
3253      * StringUtils.isAlpha("ab-c") = false
3254      * </pre>
3255      *
3256      * @param cs the CharSequence to check, may be null.
3257      * @return {@code true} if only contains letters, and is non-null.
3258      * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3259      * @since 3.0 Changed "" to return false and not true
3260      */
3261     public static boolean isAlpha(final CharSequence cs) {
3262         if (isEmpty(cs)) {
3263             return false;
3264         }
3265         final int sz = cs.length();
3266         for (int i = 0; i < sz; i++) {
3267             if (!Character.isLetter(cs.charAt(i))) {
3268                 return false;
3269             }
3270         }
3271         return true;
3272     }
3273 
3274     /**
3275      * Tests if the CharSequence contains only Unicode letters or digits.
3276      *
3277      * <p>
3278      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3279      * </p>
3280      *
3281      * <pre>
3282      * StringUtils.isAlphanumeric(null)   = false
3283      * StringUtils.isAlphanumeric("")     = false
3284      * StringUtils.isAlphanumeric("  ")   = false
3285      * StringUtils.isAlphanumeric("abc")  = true
3286      * StringUtils.isAlphanumeric("ab c") = false
3287      * StringUtils.isAlphanumeric("ab2c") = true
3288      * StringUtils.isAlphanumeric("ab-c") = false
3289      * </pre>
3290      *
3291      * @param cs the CharSequence to check, may be null.
3292      * @return {@code true} if only contains letters or digits, and is non-null.
3293      * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3294      * @since 3.0 Changed "" to return false and not true
3295      */
3296     public static boolean isAlphanumeric(final CharSequence cs) {
3297         if (isEmpty(cs)) {
3298             return false;
3299         }
3300         final int sz = cs.length();
3301         for (int i = 0; i < sz; i++) {
3302             if (!Character.isLetterOrDigit(cs.charAt(i))) {
3303                 return false;
3304             }
3305         }
3306         return true;
3307     }
3308 
3309     /**
3310      * Tests if the CharSequence contains only Unicode letters, digits or space ({@code ' '}).
3311      *
3312      * <p>
3313      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3314      * </p>
3315      *
3316      * <pre>
3317      * StringUtils.isAlphanumericSpace(null)   = false
3318      * StringUtils.isAlphanumericSpace("")     = true
3319      * StringUtils.isAlphanumericSpace("  ")   = true
3320      * StringUtils.isAlphanumericSpace("abc")  = true
3321      * StringUtils.isAlphanumericSpace("ab c") = true
3322      * StringUtils.isAlphanumericSpace("ab2c") = true
3323      * StringUtils.isAlphanumericSpace("ab-c") = false
3324      * </pre>
3325      *
3326      * @param cs the CharSequence to check, may be null.
3327      * @return {@code true} if only contains letters, digits or space, and is non-null.
3328      * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3329      */
3330     public static boolean isAlphanumericSpace(final CharSequence cs) {
3331         if (cs == null) {
3332             return false;
3333         }
3334         final int sz = cs.length();
3335         for (int i = 0; i < sz; i++) {
3336             final char nowChar = cs.charAt(i);
3337             if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar)) {
3338                 return false;
3339             }
3340         }
3341         return true;
3342     }
3343 
3344     /**
3345      * Tests if the CharSequence contains only Unicode letters and space (' ').
3346      *
3347      * <p>
3348      * {@code null} will return {@code false} An empty CharSequence (length()=0) will return {@code true}.
3349      * </p>
3350      *
3351      * <pre>
3352      * StringUtils.isAlphaSpace(null)   = false
3353      * StringUtils.isAlphaSpace("")     = true
3354      * StringUtils.isAlphaSpace("  ")   = true
3355      * StringUtils.isAlphaSpace("abc")  = true
3356      * StringUtils.isAlphaSpace("ab c") = true
3357      * StringUtils.isAlphaSpace("ab2c") = false
3358      * StringUtils.isAlphaSpace("ab-c") = false
3359      * </pre>
3360      *
3361      * @param cs the CharSequence to check, may be null.
3362      * @return {@code true} if only contains letters and space, and is non-null.
3363      * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3364      */
3365     public static boolean isAlphaSpace(final CharSequence cs) {
3366         if (cs == null) {
3367             return false;
3368         }
3369         final int sz = cs.length();
3370         for (int i = 0; i < sz; i++) {
3371             final char nowChar = cs.charAt(i);
3372             if (nowChar != ' ' && !Character.isLetter(nowChar)) {
3373                 return false;
3374             }
3375         }
3376         return true;
3377     }
3378 
3379     /**
3380      * Tests if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3381      *
3382      * <p>
3383      * Whitespace is defined by {@link Character#isWhitespace(char)}.
3384      * </p>
3385      *
3386      * <pre>
3387      * StringUtils.isAnyBlank((String) null)    = true
3388      * StringUtils.isAnyBlank((String[]) null)  = false
3389      * StringUtils.isAnyBlank(null, "foo")      = true
3390      * StringUtils.isAnyBlank(null, null)       = true
3391      * StringUtils.isAnyBlank("", "bar")        = true
3392      * StringUtils.isAnyBlank("bob", "")        = true
3393      * StringUtils.isAnyBlank("  bob  ", null)  = true
3394      * StringUtils.isAnyBlank(" ", "bar")       = true
3395      * StringUtils.isAnyBlank(new String[] {})  = false
3396      * StringUtils.isAnyBlank(new String[]{""}) = true
3397      * StringUtils.isAnyBlank("foo", "bar")     = false
3398      * </pre>
3399      *
3400      * @param css the CharSequences to check, may be null or empty.
3401      * @return {@code true} if any of the CharSequences are {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3402      * @see #isBlank(CharSequence)
3403      * @since 3.2
3404      */
3405     public static boolean isAnyBlank(final CharSequence... css) {
3406         if (ArrayUtils.isEmpty(css)) {
3407             return false;
3408         }
3409         for (final CharSequence cs : css) {
3410             if (isBlank(cs)) {
3411                 return true;
3412             }
3413         }
3414         return false;
3415     }
3416 
3417     /**
3418      * Tests if any of the CharSequences are empty ("") or null.
3419      *
3420      * <pre>
3421      * StringUtils.isAnyEmpty((String) null)    = true
3422      * StringUtils.isAnyEmpty((String[]) null)  = false
3423      * StringUtils.isAnyEmpty(null, "foo")      = true
3424      * StringUtils.isAnyEmpty("", "bar")        = true
3425      * StringUtils.isAnyEmpty("bob", "")        = true
3426      * StringUtils.isAnyEmpty("  bob  ", null)  = true
3427      * StringUtils.isAnyEmpty(" ", "bar")       = false
3428      * StringUtils.isAnyEmpty("foo", "bar")     = false
3429      * StringUtils.isAnyEmpty(new String[]{})   = false
3430      * StringUtils.isAnyEmpty(new String[]{""}) = true
3431      * </pre>
3432      *
3433      * @param css  the CharSequences to check, may be null or empty.
3434      * @return {@code true} if any of the CharSequences are empty or null.
3435      * @since 3.2
3436      */
3437     public static boolean isAnyEmpty(final CharSequence... css) {
3438         if (ArrayUtils.isEmpty(css)) {
3439             return false;
3440         }
3441         for (final CharSequence cs : css) {
3442             if (isEmpty(cs)) {
3443                 return true;
3444             }
3445         }
3446         return false;
3447     }
3448 
3449     /**
3450      * Tests if the CharSequence contains only ASCII printable characters.
3451      *
3452      * <p>
3453      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3454      * </p>
3455      *
3456      * <pre>
3457      * StringUtils.isAsciiPrintable(null)     = false
3458      * StringUtils.isAsciiPrintable("")       = true
3459      * StringUtils.isAsciiPrintable(" ")      = true
3460      * StringUtils.isAsciiPrintable("Ceki")   = true
3461      * StringUtils.isAsciiPrintable("ab2c")   = true
3462      * StringUtils.isAsciiPrintable("!ab-c~") = true
3463      * StringUtils.isAsciiPrintable("\u0020") = true
3464      * StringUtils.isAsciiPrintable("\u0021") = true
3465      * StringUtils.isAsciiPrintable("\u007e") = true
3466      * StringUtils.isAsciiPrintable("\u007f") = false
3467      * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3468      * </pre>
3469      *
3470      * @param cs the CharSequence to check, may be null.
3471      * @return {@code true} if every character is in the range 32 through 126.
3472      * @since 2.1
3473      * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3474      */
3475     public static boolean isAsciiPrintable(final CharSequence cs) {
3476         if (cs == null) {
3477             return false;
3478         }
3479         final int sz = cs.length();
3480         for (int i = 0; i < sz; i++) {
3481             if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3482                 return false;
3483             }
3484         }
3485         return true;
3486     }
3487 
3488     /**
3489      * Tests if a CharSequence is empty ({@code "")}, null, or contains only whitespace as defined by {@link Character#isWhitespace(char)}.
3490      *
3491      * <pre>
3492      * StringUtils.isBlank(null)      = true
3493      * StringUtils.isBlank("")        = true
3494      * StringUtils.isBlank(" ")       = true
3495      * StringUtils.isBlank("bob")     = false
3496      * StringUtils.isBlank("  bob  ") = false
3497      * </pre>
3498      *
3499      * @param cs the CharSequence to check, may be null.
3500      * @return {@code true} if the CharSequence is null, empty or whitespace only.
3501      * @since 2.0
3502      * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3503      */
3504     public static boolean isBlank(final CharSequence cs) {
3505         final int strLen = length(cs);
3506         if (strLen == 0) {
3507             return true;
3508         }
3509         for (int i = 0; i < strLen; i++) {
3510             if (!Character.isWhitespace(cs.charAt(i))) {
3511                 return false;
3512             }
3513         }
3514         return true;
3515     }
3516 
3517     /**
3518      * Tests if a CharSequence is empty ("") or null.
3519      *
3520      * <pre>
3521      * StringUtils.isEmpty(null)      = true
3522      * StringUtils.isEmpty("")        = true
3523      * StringUtils.isEmpty(" ")       = false
3524      * StringUtils.isEmpty("bob")     = false
3525      * StringUtils.isEmpty("  bob  ") = false
3526      * </pre>
3527      *
3528      * <p>
3529      * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is available in isBlank().
3530      * </p>
3531      *
3532      * @param cs the CharSequence to check, may be null.
3533      * @return {@code true} if the CharSequence is empty or null.
3534      * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3535      */
3536     public static boolean isEmpty(final CharSequence cs) {
3537         return cs == null || cs.length() == 0;
3538     }
3539 
3540     /**
3541      * Tests if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3542      *
3543      * <p>
3544      * {@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return {@code false}.
3545      * </p>
3546      *
3547      * <pre>
3548      * StringUtils.isMixedCase(null)    = false
3549      * StringUtils.isMixedCase("")      = false
3550      * StringUtils.isMixedCase(" ")     = false
3551      * StringUtils.isMixedCase("ABC")   = false
3552      * StringUtils.isMixedCase("abc")   = false
3553      * StringUtils.isMixedCase("aBc")   = true
3554      * StringUtils.isMixedCase("A c")   = true
3555      * StringUtils.isMixedCase("A1c")   = true
3556      * StringUtils.isMixedCase("a/C")   = true
3557      * StringUtils.isMixedCase("aC\t")  = true
3558      * </pre>
3559      *
3560      * @param cs the CharSequence to check, may be null.
3561      * @return {@code true} if the CharSequence contains both uppercase and lowercase characters.
3562      * @since 3.5
3563      */
3564     public static boolean isMixedCase(final CharSequence cs) {
3565         if (isEmpty(cs) || cs.length() == 1) {
3566             return false;
3567         }
3568         boolean containsUppercase = false;
3569         boolean containsLowercase = false;
3570         final int sz = cs.length();
3571         for (int i = 0; i < sz; i++) {
3572             final char nowChar = cs.charAt(i);
3573             if (Character.isUpperCase(nowChar)) {
3574                 containsUppercase = true;
3575             } else if (Character.isLowerCase(nowChar)) {
3576                 containsLowercase = true;
3577             }
3578             if (containsUppercase && containsLowercase) {
3579                 return true;
3580             }
3581         }
3582         return false;
3583     }
3584 
3585     /**
3586      * Tests if none of the CharSequences are empty (""), null or whitespace only.
3587      *
3588      * <p>
3589      * Whitespace is defined by {@link Character#isWhitespace(char)}.
3590      * </p>
3591      *
3592      * <pre>
3593      * StringUtils.isNoneBlank((String) null)    = false
3594      * StringUtils.isNoneBlank((String[]) null)  = true
3595      * StringUtils.isNoneBlank(null, "foo")      = false
3596      * StringUtils.isNoneBlank(null, null)       = false
3597      * StringUtils.isNoneBlank("", "bar")        = false
3598      * StringUtils.isNoneBlank("bob", "")        = false
3599      * StringUtils.isNoneBlank("  bob  ", null)  = false
3600      * StringUtils.isNoneBlank(" ", "bar")       = false
3601      * StringUtils.isNoneBlank(new String[] {})  = true
3602      * StringUtils.isNoneBlank(new String[]{""}) = false
3603      * StringUtils.isNoneBlank("foo", "bar")     = true
3604      * </pre>
3605      *
3606      * @param css the CharSequences to check, may be null or empty.
3607      * @return {@code true} if none of the CharSequences are empty or null or whitespace only.
3608      * @since 3.2
3609      */
3610     public static boolean isNoneBlank(final CharSequence... css) {
3611       return !isAnyBlank(css);
3612     }
3613 
3614     /**
3615      * Tests if none of the CharSequences are empty ("") or null.
3616      *
3617      * <pre>
3618      * StringUtils.isNoneEmpty((String) null)    = false
3619      * StringUtils.isNoneEmpty((String[]) null)  = true
3620      * StringUtils.isNoneEmpty(null, "foo")      = false
3621      * StringUtils.isNoneEmpty("", "bar")        = false
3622      * StringUtils.isNoneEmpty("bob", "")        = false
3623      * StringUtils.isNoneEmpty("  bob  ", null)  = false
3624      * StringUtils.isNoneEmpty(new String[] {})  = true
3625      * StringUtils.isNoneEmpty(new String[]{""}) = false
3626      * StringUtils.isNoneEmpty(" ", "bar")       = true
3627      * StringUtils.isNoneEmpty("foo", "bar")     = true
3628      * </pre>
3629      *
3630      * @param css  the CharSequences to check, may be null or empty.
3631      * @return {@code true} if none of the CharSequences are empty or null.
3632      * @since 3.2
3633      */
3634     public static boolean isNoneEmpty(final CharSequence... css) {
3635       return !isAnyEmpty(css);
3636     }
3637 
3638     /**
3639      * Tests if a CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3640      *
3641      * <p>
3642      * Whitespace is defined by {@link Character#isWhitespace(char)}.
3643      * </p>
3644      *
3645      * <pre>
3646      * StringUtils.isNotBlank(null)      = false
3647      * StringUtils.isNotBlank("")        = false
3648      * StringUtils.isNotBlank(" ")       = false
3649      * StringUtils.isNotBlank("bob")     = true
3650      * StringUtils.isNotBlank("  bob  ") = true
3651      * </pre>
3652      *
3653      * @param cs the CharSequence to check, may be null.
3654      * @return {@code true} if the CharSequence is not {@link #isBlank(CharSequence) blank} (whitespaces, empty ({@code ""}) or {@code null}).
3655      * @see #isBlank(CharSequence)
3656      * @since 2.0
3657      * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3658      */
3659     public static boolean isNotBlank(final CharSequence cs) {
3660         return !isBlank(cs);
3661     }
3662 
3663     /**
3664      * Tests if a CharSequence is not empty ("") and not null.
3665      *
3666      * <pre>
3667      * StringUtils.isNotEmpty(null)      = false
3668      * StringUtils.isNotEmpty("")        = false
3669      * StringUtils.isNotEmpty(" ")       = true
3670      * StringUtils.isNotEmpty("bob")     = true
3671      * StringUtils.isNotEmpty("  bob  ") = true
3672      * </pre>
3673      *
3674      * @param cs  the CharSequence to check, may be null.
3675      * @return {@code true} if the CharSequence is not empty and not null.
3676      * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3677      */
3678     public static boolean isNotEmpty(final CharSequence cs) {
3679         return !isEmpty(cs);
3680     }
3681 
3682     /**
3683      * Tests if the CharSequence contains only Unicode digits. A decimal point is not a Unicode digit and returns false.
3684      *
3685      * <p>
3686      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code false}.
3687      * </p>
3688      *
3689      * <p>
3690      * Note that the method does not allow for a leading sign, either positive or negative. Also, if a String passes the numeric test, it may still generate a
3691      * NumberFormatException when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range for int or long respectively.
3692      * </p>
3693      *
3694      * <pre>
3695      * StringUtils.isNumeric(null)   = false
3696      * StringUtils.isNumeric("")     = false
3697      * StringUtils.isNumeric("  ")   = false
3698      * StringUtils.isNumeric("123")  = true
3699      * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3700      * StringUtils.isNumeric("12 3") = false
3701      * StringUtils.isNumeric("ab2c") = false
3702      * StringUtils.isNumeric("12-3") = false
3703      * StringUtils.isNumeric("12.3") = false
3704      * StringUtils.isNumeric("-123") = false
3705      * StringUtils.isNumeric("+123") = false
3706      * </pre>
3707      *
3708      * @param cs the CharSequence to check, may be null.
3709      * @return {@code true} if only contains digits, and is non-null.
3710      * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3711      * @since 3.0 Changed "" to return false and not true
3712      */
3713     public static boolean isNumeric(final CharSequence cs) {
3714         if (isEmpty(cs)) {
3715             return false;
3716         }
3717         final int sz = cs.length();
3718         for (int i = 0; i < sz; i++) {
3719             if (!Character.isDigit(cs.charAt(i))) {
3720                 return false;
3721             }
3722         }
3723         return true;
3724     }
3725 
3726     /**
3727      * Tests if the CharSequence contains only Unicode digits or space ({@code ' '}). A decimal point is not a Unicode digit and returns false.
3728      *
3729      * <p>
3730      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3731      * </p>
3732      *
3733      * <pre>
3734      * StringUtils.isNumericSpace(null)   = false
3735      * StringUtils.isNumericSpace("")     = true
3736      * StringUtils.isNumericSpace("  ")   = true
3737      * StringUtils.isNumericSpace("123")  = true
3738      * StringUtils.isNumericSpace("12 3") = true
3739      * StringUtils.isNumericSpace("\u0967\u0968\u0969")   = true
3740      * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3741      * StringUtils.isNumericSpace("ab2c") = false
3742      * StringUtils.isNumericSpace("12-3") = false
3743      * StringUtils.isNumericSpace("12.3") = false
3744      * </pre>
3745      *
3746      * @param cs the CharSequence to check, may be null.
3747      * @return {@code true} if only contains digits or space, and is non-null.
3748      * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3749      */
3750     public static boolean isNumericSpace(final CharSequence cs) {
3751         if (cs == null) {
3752             return false;
3753         }
3754         final int sz = cs.length();
3755         for (int i = 0; i < sz; i++) {
3756             final char nowChar = cs.charAt(i);
3757             if (nowChar != ' ' && !Character.isDigit(nowChar)) {
3758                 return false;
3759             }
3760         }
3761         return true;
3762     }
3763 
3764     /**
3765      * Tests if the CharSequence contains only whitespace.
3766      *
3767      * <p>
3768      * Whitespace is defined by {@link Character#isWhitespace(char)}.
3769      * </p>
3770      *
3771      * <p>
3772      * {@code null} will return {@code false}. An empty CharSequence (length()=0) will return {@code true}.
3773      * </p>
3774      *
3775      * <pre>
3776      * StringUtils.isWhitespace(null)   = false
3777      * StringUtils.isWhitespace("")     = true
3778      * StringUtils.isWhitespace("  ")   = true
3779      * StringUtils.isWhitespace("abc")  = false
3780      * StringUtils.isWhitespace("ab2c") = false
3781      * StringUtils.isWhitespace("ab-c") = false
3782      * </pre>
3783      *
3784      * @param cs the CharSequence to check, may be null.
3785      * @return {@code true} if only contains whitespace, and is non-null.
3786      * @since 2.0
3787      * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3788      */
3789     public static boolean isWhitespace(final CharSequence cs) {
3790         if (cs == null) {
3791             return false;
3792         }
3793         final int sz = cs.length();
3794         for (int i = 0; i < sz; i++) {
3795             if (!Character.isWhitespace(cs.charAt(i))) {
3796                 return false;
3797             }
3798         }
3799         return true;
3800     }
3801 
3802     /**
3803      * Joins the elements of the provided array into a single String containing the provided list of elements.
3804      *
3805      * <p>
3806      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
3807      * </p>
3808      *
3809      * <pre>
3810      * StringUtils.join(null, *)             = null
3811      * StringUtils.join([], *)               = ""
3812      * StringUtils.join([null], *)           = ""
3813      * StringUtils.join([false, false], ';') = "false;false"
3814      * </pre>
3815      *
3816      * @param array     the array of values to join together, may be null.
3817      * @param delimiter the separator character to use.
3818      * @return the joined String, {@code null} if null array input.
3819      * @since 3.12.0
3820      */
3821     public static String join(final boolean[] array, final char delimiter) {
3822         if (array == null) {
3823             return null;
3824         }
3825         return join(array, delimiter, 0, array.length);
3826     }
3827 
3828     /**
3829      * Joins the elements of the provided array into a single String containing the provided list of elements.
3830      *
3831      * <p>
3832      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3833      * by empty strings.
3834      * </p>
3835      *
3836      * <pre>
3837      * StringUtils.join(null, *)                  = null
3838      * StringUtils.join([], *)                    = ""
3839      * StringUtils.join([null], *)                = ""
3840      * StringUtils.join([true, false, true], ';') = "true;false;true"
3841      * </pre>
3842      *
3843      * @param array
3844      *            the array of values to join together, may be null.
3845      * @param delimiter
3846      *            the separator character to use.
3847      * @param startIndex
3848      *            the first index to start joining from. It is an error to pass in a start index past the end of the
3849      *            array.
3850      * @param endIndex
3851      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3852      *            the array.
3853      * @return the joined String, {@code null} if null array input.
3854      * @since 3.12.0
3855      */
3856     public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3857         if (array == null) {
3858             return null;
3859         }
3860         if (endIndex - startIndex <= 0) {
3861             return EMPTY;
3862         }
3863         final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
3864         for (int i = startIndex; i < endIndex; i++) {
3865             stringBuilder
3866                     .append(array[i])
3867                     .append(delimiter);
3868         }
3869         return stringBuilder.substring(0, stringBuilder.length() - 1);
3870     }
3871 
3872     /**
3873      * Joins the elements of the provided array into a single String containing the provided list of elements.
3874      *
3875      * <p>
3876      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3877      * by empty strings.
3878      * </p>
3879      *
3880      * <pre>
3881      * StringUtils.join(null, *)         = null
3882      * StringUtils.join([], *)           = ""
3883      * StringUtils.join([null], *)       = ""
3884      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3885      * StringUtils.join([1, 2, 3], null) = "123"
3886      * </pre>
3887      *
3888      * @param array
3889      *            the array of values to join together, may be null.
3890      * @param delimiter
3891      *            the separator character to use.
3892      * @return the joined String, {@code null} if null array input.
3893      * @since 3.2
3894      */
3895     public static String join(final byte[] array, final char delimiter) {
3896         if (array == null) {
3897             return null;
3898         }
3899         return join(array, delimiter, 0, array.length);
3900     }
3901 
3902     /**
3903      * Joins the elements of the provided array into a single String containing the provided list of elements.
3904      *
3905      * <p>
3906      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3907      * by empty strings.
3908      * </p>
3909      *
3910      * <pre>
3911      * StringUtils.join(null, *)         = null
3912      * StringUtils.join([], *)           = ""
3913      * StringUtils.join([null], *)       = ""
3914      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3915      * StringUtils.join([1, 2, 3], null) = "123"
3916      * </pre>
3917      *
3918      * @param array
3919      *            the array of values to join together, may be null.
3920      * @param delimiter
3921      *            the separator character to use.
3922      * @param startIndex
3923      *            the first index to start joining from. It is an error to pass in a start index past the end of the
3924      *            array.
3925      * @param endIndex
3926      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3927      *            the array.
3928      * @return the joined String, {@code null} if null array input.
3929      * @since 3.2
3930      */
3931     public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
3932         if (array == null) {
3933             return null;
3934         }
3935         if (endIndex - startIndex <= 0) {
3936             return EMPTY;
3937         }
3938         final StringBuilder stringBuilder = new StringBuilder();
3939         for (int i = startIndex; i < endIndex; i++) {
3940             stringBuilder
3941                     .append(array[i])
3942                     .append(delimiter);
3943         }
3944         return stringBuilder.substring(0, stringBuilder.length() - 1);
3945     }
3946 
3947     /**
3948      * Joins the elements of the provided array into a single String containing the provided list of elements.
3949      *
3950      * <p>
3951      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3952      * by empty strings.
3953      * </p>
3954      *
3955      * <pre>
3956      * StringUtils.join(null, *)         = null
3957      * StringUtils.join([], *)           = ""
3958      * StringUtils.join([null], *)       = ""
3959      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3960      * StringUtils.join([1, 2, 3], null) = "123"
3961      * </pre>
3962      *
3963      * @param array
3964      *            the array of values to join together, may be null.
3965      * @param delimiter
3966      *            the separator character to use.
3967      * @return the joined String, {@code null} if null array input.
3968      * @since 3.2
3969      */
3970     public static String join(final char[] array, final char delimiter) {
3971         if (array == null) {
3972             return null;
3973         }
3974         return join(array, delimiter, 0, array.length);
3975     }
3976 
3977     /**
3978      * Joins the elements of the provided array into a single String containing the provided list of elements.
3979      *
3980      * <p>
3981      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3982      * by empty strings.
3983      * </p>
3984      *
3985      * <pre>
3986      * StringUtils.join(null, *)         = null
3987      * StringUtils.join([], *)           = ""
3988      * StringUtils.join([null], *)       = ""
3989      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3990      * StringUtils.join([1, 2, 3], null) = "123"
3991      * </pre>
3992      *
3993      * @param array
3994      *            the array of values to join together, may be null.
3995      * @param delimiter
3996      *            the separator character to use.
3997      * @param startIndex
3998      *            the first index to start joining from. It is an error to pass in a start index past the end of the
3999      *            array.
4000      * @param endIndex
4001      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4002      *            the array.
4003      * @return the joined String, {@code null} if null array input.
4004      * @since 3.2
4005      */
4006     public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
4007         if (array == null) {
4008             return null;
4009         }
4010         if (endIndex - startIndex <= 0) {
4011             return EMPTY;
4012         }
4013         final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
4014         for (int i = startIndex; i < endIndex; i++) {
4015             stringBuilder
4016                     .append(array[i])
4017                     .append(delimiter);
4018         }
4019         return stringBuilder.substring(0, stringBuilder.length() - 1);
4020     }
4021 
4022     /**
4023      * Joins the elements of the provided array into a single String containing the provided list of elements.
4024      *
4025      * <p>
4026      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4027      * by empty strings.
4028      * </p>
4029      *
4030      * <pre>
4031      * StringUtils.join(null, *)          = null
4032      * StringUtils.join([], *)            = ""
4033      * StringUtils.join([null], *)        = ""
4034      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4035      * StringUtils.join([1, 2, 3], null)  = "123"
4036      * </pre>
4037      *
4038      * @param array
4039      *            the array of values to join together, may be null.
4040      * @param delimiter
4041      *            the separator character to use.
4042      * @return the joined String, {@code null} if null array input.
4043      * @since 3.2
4044      */
4045     public static String join(final double[] array, final char delimiter) {
4046         if (array == null) {
4047             return null;
4048         }
4049         return join(array, delimiter, 0, array.length);
4050     }
4051 
4052     /**
4053      * Joins the elements of the provided array into a single String containing the provided list of elements.
4054      *
4055      * <p>
4056      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4057      * by empty strings.
4058      * </p>
4059      *
4060      * <pre>
4061      * StringUtils.join(null, *)          = null
4062      * StringUtils.join([], *)            = ""
4063      * StringUtils.join([null], *)        = ""
4064      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4065      * StringUtils.join([1, 2, 3], null)  = "123"
4066      * </pre>
4067      *
4068      * @param array
4069      *            the array of values to join together, may be null.
4070      * @param delimiter
4071      *            the separator character to use.
4072      * @param startIndex
4073      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4074      *            array.
4075      * @param endIndex
4076      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4077      *            the array.
4078      * @return the joined String, {@code null} if null array input.
4079      * @since 3.2
4080      */
4081     public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4082         if (array == null) {
4083             return null;
4084         }
4085         if (endIndex - startIndex <= 0) {
4086             return EMPTY;
4087         }
4088         final StringBuilder stringBuilder = new StringBuilder();
4089         for (int i = startIndex; i < endIndex; i++) {
4090             stringBuilder
4091                     .append(array[i])
4092                     .append(delimiter);
4093         }
4094         return stringBuilder.substring(0, stringBuilder.length() - 1);
4095     }
4096 
4097     /**
4098      * Joins the elements of the provided array into a single String containing the provided list of elements.
4099      *
4100      * <p>
4101      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4102      * by empty strings.
4103      * </p>
4104      *
4105      * <pre>
4106      * StringUtils.join(null, *)          = null
4107      * StringUtils.join([], *)            = ""
4108      * StringUtils.join([null], *)        = ""
4109      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4110      * StringUtils.join([1, 2, 3], null)  = "123"
4111      * </pre>
4112      *
4113      * @param array
4114      *            the array of values to join together, may be null.
4115      * @param delimiter
4116      *            the separator character to use.
4117      * @return the joined String, {@code null} if null array input
4118      * @since 3.2
4119      */
4120     public static String join(final float[] array, final char delimiter) {
4121         if (array == null) {
4122             return null;
4123         }
4124         return join(array, delimiter, 0, array.length);
4125     }
4126 
4127     /**
4128      * Joins the elements of the provided array into a single String containing the provided list of elements.
4129      *
4130      * <p>
4131      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4132      * by empty strings.
4133      * </p>
4134      *
4135      * <pre>
4136      * StringUtils.join(null, *)          = null
4137      * StringUtils.join([], *)            = ""
4138      * StringUtils.join([null], *)        = ""
4139      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4140      * StringUtils.join([1, 2, 3], null)  = "123"
4141      * </pre>
4142      *
4143      * @param array
4144      *            the array of values to join together, may be null.
4145      * @param delimiter
4146      *            the separator character to use.
4147      * @param startIndex
4148      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4149      *            array.
4150      * @param endIndex
4151      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4152      *            the array.
4153      * @return the joined String, {@code null} if null array input.
4154      * @since 3.2
4155      */
4156     public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4157         if (array == null) {
4158             return null;
4159         }
4160         if (endIndex - startIndex <= 0) {
4161             return EMPTY;
4162         }
4163         final StringBuilder stringBuilder = new StringBuilder();
4164         for (int i = startIndex; i < endIndex; i++) {
4165             stringBuilder
4166                     .append(array[i])
4167                     .append(delimiter);
4168         }
4169         return stringBuilder.substring(0, stringBuilder.length() - 1);
4170     }
4171 
4172     /**
4173      * Joins the elements of the provided array into a single String containing the provided list of elements.
4174      *
4175      * <p>
4176      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4177      * by empty strings.
4178      * </p>
4179      *
4180      * <pre>
4181      * StringUtils.join(null, *)          = null
4182      * StringUtils.join([], *)            = ""
4183      * StringUtils.join([null], *)        = ""
4184      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4185      * StringUtils.join([1, 2, 3], null)  = "123"
4186      * </pre>
4187      *
4188      * @param array
4189      *            the array of values to join together, may be null.
4190      * @param separator
4191      *            the separator character to use.
4192      * @return the joined String, {@code null} if null array input.
4193      * @since 3.2
4194      */
4195     public static String join(final int[] array, final char separator) {
4196         if (array == null) {
4197             return null;
4198         }
4199         return join(array, separator, 0, array.length);
4200     }
4201 
4202     /**
4203      * Joins the elements of the provided array into a single String containing the provided list of elements.
4204      *
4205      * <p>
4206      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4207      * by empty strings.
4208      * </p>
4209      *
4210      * <pre>
4211      * StringUtils.join(null, *)          = null
4212      * StringUtils.join([], *)            = ""
4213      * StringUtils.join([null], *)        = ""
4214      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4215      * StringUtils.join([1, 2, 3], null)  = "123"
4216      * </pre>
4217      *
4218      * @param array
4219      *            the array of values to join together, may be null.
4220      * @param delimiter
4221      *            the separator character to use.
4222      * @param startIndex
4223      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4224      *            array.
4225      * @param endIndex
4226      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4227      *            the array.
4228      * @return the joined String, {@code null} if null array input.
4229      * @since 3.2
4230      */
4231     public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4232         if (array == null) {
4233             return null;
4234         }
4235         if (endIndex - startIndex <= 0) {
4236             return EMPTY;
4237         }
4238         final StringBuilder stringBuilder = new StringBuilder();
4239         for (int i = startIndex; i < endIndex; i++) {
4240             stringBuilder
4241                     .append(array[i])
4242                     .append(delimiter);
4243         }
4244         return stringBuilder.substring(0, stringBuilder.length() - 1);
4245     }
4246 
4247     /**
4248      * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4249      *
4250      * <p>
4251      * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4252      * </p>
4253      *
4254      * <p>
4255      * See the examples here: {@link #join(Object[],char)}.
4256      * </p>
4257      *
4258      * @param iterable  the {@link Iterable} providing the values to join together, may be null.
4259      * @param separator the separator character to use.
4260      * @return the joined String, {@code null} if null iterator input.
4261      * @since 2.3
4262      */
4263     public static String join(final Iterable<?> iterable, final char separator) {
4264         return iterable != null ? join(iterable.iterator(), separator) : null;
4265     }
4266 
4267     /**
4268      * Joins the elements of the provided {@link Iterable} into a single String containing the provided elements.
4269      *
4270      * <p>
4271      * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4272      * </p>
4273      *
4274      * <p>
4275      * See the examples here: {@link #join(Object[],String)}.
4276      * </p>
4277      *
4278      * @param iterable  the {@link Iterable} providing the values to join together, may be null.
4279      * @param separator the separator character to use, null treated as "".
4280      * @return the joined String, {@code null} if null iterator input.
4281      * @since 2.3
4282      */
4283     public static String join(final Iterable<?> iterable, final String separator) {
4284         return iterable != null ? join(iterable.iterator(), separator) : null;
4285     }
4286 
4287     /**
4288      * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4289      *
4290      * <p>
4291      * No delimiter is added before or after the list. Null objects or empty strings within the iteration are represented by empty strings.
4292      * </p>
4293      *
4294      * <p>
4295      * See the examples here: {@link #join(Object[],char)}.
4296      * </p>
4297      *
4298      * @param iterator  the {@link Iterator} of values to join together, may be null.
4299      * @param separator the separator character to use.
4300      * @return the joined String, {@code null} if null iterator input.
4301      * @since 2.0
4302      */
4303     public static String join(final Iterator<?> iterator, final char separator) {
4304         // handle null, zero and one elements before building a buffer
4305         if (iterator == null) {
4306             return null;
4307         }
4308         if (!iterator.hasNext()) {
4309             return EMPTY;
4310         }
4311         return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(String.valueOf(separator)), EMPTY, EMPTY, ObjectUtils::toString));
4312     }
4313 
4314     /**
4315      * Joins the elements of the provided {@link Iterator} into a single String containing the provided elements.
4316      *
4317      * <p>
4318      * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String ("").
4319      * </p>
4320      *
4321      * <p>
4322      * See the examples here: {@link #join(Object[],String)}.
4323      * </p>
4324      *
4325      * @param iterator  the {@link Iterator} of values to join together, may be null.
4326      * @param separator the separator character to use, null treated as "".
4327      * @return the joined String, {@code null} if null iterator input.
4328      */
4329     public static String join(final Iterator<?> iterator, final String separator) {
4330         // handle null, zero and one elements before building a buffer
4331         if (iterator == null) {
4332             return null;
4333         }
4334         if (!iterator.hasNext()) {
4335             return EMPTY;
4336         }
4337         return Streams.of(iterator).collect(LangCollectors.joining(ObjectUtils.toString(separator), EMPTY, EMPTY, ObjectUtils::toString));
4338     }
4339 
4340     /**
4341      * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4342      *
4343      * <p>
4344      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4345      * </p>
4346      *
4347      * <pre>
4348      * StringUtils.join(null, *)               = null
4349      * StringUtils.join([], *)                 = ""
4350      * StringUtils.join([null], *)             = ""
4351      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4352      * StringUtils.join(["a", "b", "c"], null) = "abc"
4353      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4354      * </pre>
4355      *
4356      * @param list       the {@link List} of values to join together, may be null.
4357      * @param separator  the separator character to use.
4358      * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the list.
4359      * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the list.
4360      * @return the joined String, {@code null} if null list input.
4361      * @since 3.8
4362      */
4363     public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4364         if (list == null) {
4365             return null;
4366         }
4367         final int noOfItems = endIndex - startIndex;
4368         if (noOfItems <= 0) {
4369             return EMPTY;
4370         }
4371         final List<?> subList = list.subList(startIndex, endIndex);
4372         return join(subList.iterator(), separator);
4373     }
4374 
4375     /**
4376      * Joins the elements of the provided {@link List} into a single String containing the provided list of elements.
4377      *
4378      * <p>
4379      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4380      * </p>
4381      *
4382      * <pre>
4383      * StringUtils.join(null, *)               = null
4384      * StringUtils.join([], *)                 = ""
4385      * StringUtils.join([null], *)             = ""
4386      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4387      * StringUtils.join(["a", "b", "c"], null) = "abc"
4388      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4389      * </pre>
4390      *
4391      * @param list       the {@link List} of values to join together, may be null.
4392      * @param separator  the separator character to use.
4393      * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the list.
4394      * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the list.
4395      * @return the joined String, {@code null} if null list input.
4396      * @since 3.8
4397      */
4398     public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4399         if (list == null) {
4400             return null;
4401         }
4402         final int noOfItems = endIndex - startIndex;
4403         if (noOfItems <= 0) {
4404             return EMPTY;
4405         }
4406         final List<?> subList = list.subList(startIndex, endIndex);
4407         return join(subList.iterator(), separator);
4408     }
4409 
4410     /**
4411      * Joins the elements of the provided array into a single String containing the provided list of elements.
4412      *
4413      * <p>
4414      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4415      * by empty strings.
4416      * </p>
4417      *
4418      * <pre>
4419      * StringUtils.join(null, *)               = null
4420      * StringUtils.join([], *)                 = ""
4421      * StringUtils.join([null], *)             = ""
4422      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4423      * StringUtils.join([1, 2, 3], null) = "123"
4424      * </pre>
4425      *
4426      * @param array
4427      *            the array of values to join together, may be null.
4428      * @param separator
4429      *            the separator character to use.
4430      * @return the joined String, {@code null} if null array input.
4431      * @since 3.2
4432      */
4433     public static String join(final long[] array, final char separator) {
4434         if (array == null) {
4435             return null;
4436         }
4437         return join(array, separator, 0, array.length);
4438     }
4439 
4440     /**
4441      * Joins the elements of the provided array into a single String containing the provided list of elements.
4442      *
4443      * <p>
4444      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4445      * by empty strings.
4446      * </p>
4447      *
4448      * <pre>
4449      * StringUtils.join(null, *)               = null
4450      * StringUtils.join([], *)                 = ""
4451      * StringUtils.join([null], *)             = ""
4452      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4453      * StringUtils.join([1, 2, 3], null) = "123"
4454      * </pre>
4455      *
4456      * @param array
4457      *            the array of values to join together, may be null.
4458      * @param delimiter
4459      *            the separator character to use.
4460      * @param startIndex
4461      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4462      *            array.
4463      * @param endIndex
4464      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4465      *            the array.
4466      * @return the joined String, {@code null} if null array input.
4467      * @since 3.2
4468      */
4469     public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4470         if (array == null) {
4471             return null;
4472         }
4473         if (endIndex - startIndex <= 0) {
4474             return EMPTY;
4475         }
4476         final StringBuilder stringBuilder = new StringBuilder();
4477         for (int i = startIndex; i < endIndex; i++) {
4478             stringBuilder
4479                     .append(array[i])
4480                     .append(delimiter);
4481         }
4482         return stringBuilder.substring(0, stringBuilder.length() - 1);
4483     }
4484 
4485     /**
4486      * Joins the elements of the provided array into a single String containing the provided list of elements.
4487      *
4488      * <p>
4489      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4490      * </p>
4491      *
4492      * <pre>
4493      * StringUtils.join(null, *)               = null
4494      * StringUtils.join([], *)                 = ""
4495      * StringUtils.join([null], *)             = ""
4496      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4497      * StringUtils.join(["a", "b", "c"], null) = "abc"
4498      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4499      * </pre>
4500      *
4501      * @param array     the array of values to join together, may be null.
4502      * @param delimiter the separator character to use.
4503      * @return the joined String, {@code null} if null array input.
4504      * @since 2.0
4505      */
4506     public static String join(final Object[] array, final char delimiter) {
4507         if (array == null) {
4508             return null;
4509         }
4510         return join(array, delimiter, 0, array.length);
4511     }
4512 
4513     /**
4514      * Joins the elements of the provided array into a single String containing the provided list of elements.
4515      *
4516      * <p>
4517      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented by empty strings.
4518      * </p>
4519      *
4520      * <pre>
4521      * StringUtils.join(null, *)               = null
4522      * StringUtils.join([], *)                 = ""
4523      * StringUtils.join([null], *)             = ""
4524      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4525      * StringUtils.join(["a", "b", "c"], null) = "abc"
4526      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4527      * </pre>
4528      *
4529      * @param array      the array of values to join together, may be null.
4530      * @param delimiter  the separator character to use.
4531      * @param startIndex the first index to start joining from. It is an error to pass in a start index past the end of the array.
4532      * @param endIndex   the index to stop joining from (exclusive). It is an error to pass in an end index past the end of the array.
4533      * @return the joined String, {@code null} if null array input.
4534      * @since 2.0
4535      */
4536     public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4537         return join(array, String.valueOf(delimiter), startIndex, endIndex);
4538     }
4539 
4540     /**
4541      * Joins the elements of the provided array into a single String containing the provided list of elements.
4542      *
4543      * <p>
4544      * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
4545      * array are represented by empty strings.
4546      * </p>
4547      *
4548      * <pre>
4549      * StringUtils.join(null, *)                = null
4550      * StringUtils.join([], *)                  = ""
4551      * StringUtils.join([null], *)              = ""
4552      * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4553      * StringUtils.join(["a", "b", "c"], null)  = "abc"
4554      * StringUtils.join(["a", "b", "c"], "")    = "abc"
4555      * StringUtils.join([null, "", "a"], ',')   = ",,a"
4556      * </pre>
4557      *
4558      * @param array     the array of values to join together, may be null.
4559      * @param delimiter the separator character to use, null treated as "".
4560      * @return the joined String, {@code null} if null array input.
4561      */
4562     public static String join(final Object[] array, final String delimiter) {
4563         return array != null ? join(array, ObjectUtils.toString(delimiter), 0, array.length) : null;
4564     }
4565 
4566     /**
4567      * Joins the elements of the provided array into a single String containing the provided list of elements.
4568      *
4569      * <p>
4570      * No delimiter is added before or after the list. A {@code null} separator is the same as an empty String (""). Null objects or empty strings within the
4571      * array are represented by empty strings.
4572      * </p>
4573      *
4574      * <pre>
4575      * StringUtils.join(null, *, *, *)                = null
4576      * StringUtils.join([], *, *, *)                  = ""
4577      * StringUtils.join([null], *, *, *)              = ""
4578      * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4579      * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4580      * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4581      * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4582      * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4583      * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4584      * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4585      * </pre>
4586      *
4587      * @param array      the array of values to join together, may be null.
4588      * @param delimiter  the separator character to use, null treated as "".
4589      * @param startIndex the first index to start joining from.
4590      * @param endIndex   the index to stop joining from (exclusive).
4591      * @return the joined String, {@code null} if null array input; or the empty string if {@code endIndex - startIndex <= 0}. The number of joined entries is
4592      *         given by {@code endIndex - startIndex}.
4593      * @throws ArrayIndexOutOfBoundsException ife<br>
4594      *                                        {@code startIndex < 0} or <br>
4595      *                                        {@code startIndex >= array.length()} or <br>
4596      *                                        {@code endIndex < 0} or <br>
4597      *                                        {@code endIndex > array.length()}
4598      */
4599     public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4600         return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4601                 .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, ObjectUtils::toString)) : null;
4602     }
4603 
4604     /**
4605      * Joins the elements of the provided array into a single String containing the provided list of elements.
4606      *
4607      * <p>
4608      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4609      * by empty strings.
4610      * </p>
4611      *
4612      * <pre>
4613      * StringUtils.join(null, *)          = null
4614      * StringUtils.join([], *)            = ""
4615      * StringUtils.join([null], *)        = ""
4616      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4617      * StringUtils.join([1, 2, 3], null)  = "123"
4618      * </pre>
4619      *
4620      * @param array
4621      *            the array of values to join together, may be null.
4622      * @param delimiter
4623      *            the separator character to use.
4624      * @return the joined String, {@code null} if null array input.
4625      * @since 3.2
4626      */
4627     public static String join(final short[] array, final char delimiter) {
4628         if (array == null) {
4629             return null;
4630         }
4631         return join(array, delimiter, 0, array.length);
4632     }
4633 
4634     /**
4635      * Joins the elements of the provided array into a single String containing the provided list of elements.
4636      *
4637      * <p>
4638      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4639      * by empty strings.
4640      * </p>
4641      *
4642      * <pre>
4643      * StringUtils.join(null, *)          = null
4644      * StringUtils.join([], *)            = ""
4645      * StringUtils.join([null], *)        = ""
4646      * StringUtils.join([1, 2, 3], ';')   = "1;2;3"
4647      * StringUtils.join([1, 2, 3], null)  = "123"
4648      * </pre>
4649      *
4650      * @param array
4651      *            the array of values to join together, may be null.
4652      * @param delimiter
4653      *            the separator character to use.
4654      * @param startIndex
4655      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4656      *            array.
4657      * @param endIndex
4658      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4659      *            the array.
4660      * @return the joined String, {@code null} if null array input.
4661      * @since 3.2
4662      */
4663     public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4664         if (array == null) {
4665             return null;
4666         }
4667         if (endIndex - startIndex <= 0) {
4668             return EMPTY;
4669         }
4670         final StringBuilder stringBuilder = new StringBuilder();
4671         for (int i = startIndex; i < endIndex; i++) {
4672             stringBuilder
4673                     .append(array[i])
4674                     .append(delimiter);
4675         }
4676         return stringBuilder.substring(0, stringBuilder.length() - 1);
4677     }
4678 
4679     /**
4680      * Joins the elements of the provided array into a single String containing the provided list of elements.
4681      *
4682      * <p>
4683      * No separator is added to the joined String. Null objects or empty strings within the array are represented by empty strings.
4684      * </p>
4685      *
4686      * <pre>
4687      * StringUtils.join(null)            = null
4688      * StringUtils.join([])              = ""
4689      * StringUtils.join([null])          = ""
4690      * StringUtils.join(["a", "b", "c"]) = "abc"
4691      * StringUtils.join([null, "", "a"]) = "a"
4692      * </pre>
4693      *
4694      * @param <T>      the specific type of values to join together.
4695      * @param elements the values to join together, may be null.
4696      * @return the joined String, {@code null} if null array input.
4697      * @since 2.0
4698      * @since 3.0 Changed signature to use varargs
4699      */
4700     @SafeVarargs
4701     public static <T> String join(final T... elements) {
4702         return join(elements, null);
4703     }
4704 
4705     /**
4706      * Joins the elements of the provided varargs into a single String containing the provided elements.
4707      *
4708      * <p>
4709      * No delimiter is added before or after the list. {@code null} elements and separator are treated as empty Strings ("").
4710      * </p>
4711      *
4712      * <pre>
4713      * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4714      * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4715      * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4716      * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4717      * </pre>
4718      *
4719      * @param delimiter the separator character to use, null treated as "".
4720      * @param array     the varargs providing the values to join together. {@code null} elements are treated as "".
4721      * @return the joined String.
4722      * @throws IllegalArgumentException if a null varargs is provided.
4723      * @since 3.5
4724      */
4725     public static String joinWith(final String delimiter, final Object... array) {
4726         if (array == null) {
4727             throw new IllegalArgumentException("Object varargs must not be null");
4728         }
4729         return join(array, delimiter);
4730     }
4731 
4732     /**
4733      * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String)} if possible.
4734      *
4735      * <p>
4736      * A {@code null} CharSequence will return {@code -1}.
4737      * </p>
4738      *
4739      * <pre>
4740      * StringUtils.lastIndexOf(null, *)          = -1
4741      * StringUtils.lastIndexOf(*, null)          = -1
4742      * StringUtils.lastIndexOf("", "")           = 0
4743      * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4744      * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4745      * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4746      * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4747      * </pre>
4748      *
4749      * @param seq       the CharSequence to check, may be null.
4750      * @param searchSeq the CharSequence to find, may be null.
4751      * @return the last index of the search String, -1 if no match or {@code null} string input.
4752      * @since 2.0
4753      * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4754      * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CS.lastIndexOf(CharSequence, CharSequence)}
4755      */
4756     @Deprecated
4757     public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4758         return Strings.CS.lastIndexOf(seq, searchSeq);
4759     }
4760 
4761     /**
4762      * Finds the last index within a CharSequence, handling {@code null}. This method uses {@link String#lastIndexOf(String, int)} if possible.
4763      *
4764      * <p>
4765      * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4766      * the start position is negative. A start position greater than the string length searches the whole string. The search starts at the startPos and works
4767      * backwards; matches starting after the start position are ignored.
4768      * </p>
4769      *
4770      * <pre>
4771      * StringUtils.lastIndexOf(null, *, *)          = -1
4772      * StringUtils.lastIndexOf(*, null, *)          = -1
4773      * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4774      * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4775      * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4776      * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4777      * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4778      * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4779      * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4780      * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4781      * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4782      * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4783      * </pre>
4784      *
4785      * @param seq       the CharSequence to check, may be null.
4786      * @param searchSeq the CharSequence to find, may be null.
4787      * @param startPos  the start position, negative treated as zero.
4788      * @return the last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} string input.
4789      * @since 2.0
4790      * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4791      * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CS.lastIndexOf(CharSequence, CharSequence, int)}
4792      */
4793     @Deprecated
4794     public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4795         return Strings.CS.lastIndexOf(seq, searchSeq, startPos);
4796     }
4797 
4798     /**
4799      * Returns the index within {@code seq} of the last occurrence of the specified character. For values of {@code searchChar} in the range from 0 to 0xFFFF
4800      * (inclusive), the index (in Unicode code units) returned is the largest value <em>k</em> such that:
4801      *
4802      * <pre>
4803      * this.charAt(<em>k</em>) == searchChar
4804      * </pre>
4805      *
4806      * <p>
4807      * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4808      * </p>
4809      *
4810      * <pre>
4811      * this.codePointAt(<em>k</em>) == searchChar
4812      * </pre>
4813      *
4814      * <p>
4815      * is true. In either case, if no such character occurs in this string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4816      * {@link CharSequence} will return {@code -1}. The {@code seq} {@link CharSequence} object is searched backwards starting at the last character.
4817      * </p>
4818      *
4819      * <pre>
4820      * StringUtils.lastIndexOf(null, *)         = -1
4821      * StringUtils.lastIndexOf("", *)           = -1
4822      * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4823      * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4824      * </pre>
4825      *
4826      * @param seq        the {@link CharSequence} to check, may be null.
4827      * @param searchChar the character to find.
4828      * @return the last index of the search character, -1 if no match or {@code null} string input.
4829      * @since 2.0
4830      * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4831      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4832      */
4833     public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4834         if (isEmpty(seq)) {
4835             return INDEX_NOT_FOUND;
4836         }
4837         return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4838     }
4839 
4840     /**
4841      * Returns the index within {@code seq} of the last occurrence of the specified character, searching backward starting at the specified index. For values of
4842      * {@code searchChar} in the range from 0 to 0xFFFF (inclusive), the index returned is the largest value <em>k</em> such that:
4843      *
4844      * <pre>
4845      * (this.charAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4846      * </pre>
4847      *
4848      * <p>
4849      * is true. For other values of {@code searchChar}, it is the largest value <em>k</em> such that:
4850      * </p>
4851      *
4852      * <pre>
4853      * (this.codePointAt(<em>k</em>) == searchChar) &amp;&amp; (<em>k</em> &lt;= startPos)
4854      * </pre>
4855      *
4856      * <p>
4857      * is true. In either case, if no such character occurs in {@code seq} at or before position {@code startPos}, then {@code -1} is returned. Furthermore, a
4858      * {@code null} or empty ("") {@link CharSequence} will return {@code -1}. A start position greater than the string length searches the whole string. The
4859      * search starts at the {@code startPos} and works backwards; matches starting after the start position are ignored.
4860      * </p>
4861      *
4862      * <p>
4863      * All indices are specified in {@code char} values (Unicode code units).
4864      * </p>
4865      *
4866      * <pre>
4867      * StringUtils.lastIndexOf(null, *, *)          = -1
4868      * StringUtils.lastIndexOf("", *,  *)           = -1
4869      * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4870      * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4871      * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4872      * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4873      * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4874      * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4875      * </pre>
4876      *
4877      * @param seq        the CharSequence to check, may be null.
4878      * @param searchChar the character to find.
4879      * @param startPos   the start position.
4880      * @return the last index of the search character (always &le; startPos), -1 if no match or {@code null} string input.
4881      * @since 2.0
4882      * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
4883      */
4884     public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
4885         if (isEmpty(seq)) {
4886             return INDEX_NOT_FOUND;
4887         }
4888         return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
4889     }
4890 
4891     /**
4892      * Finds the latest index of any substring in a set of potential substrings.
4893      *
4894      * <p>
4895      * A {@code null} CharSequence will return {@code -1}. A {@code null} search array will return {@code -1}. A {@code null} or zero length search array entry
4896      * will be ignored, but a search array containing "" will return the length of {@code str} if {@code str} is not null. This method uses
4897      * {@link String#indexOf(String)} if possible
4898      * </p>
4899      *
4900      * <pre>
4901      * StringUtils.lastIndexOfAny(null, *)                    = -1
4902      * StringUtils.lastIndexOfAny(*, null)                    = -1
4903      * StringUtils.lastIndexOfAny(*, [])                      = -1
4904      * StringUtils.lastIndexOfAny(*, [null])                  = -1
4905      * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
4906      * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
4907      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4908      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4909      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
4910      * </pre>
4911      *
4912      * @param str        the CharSequence to check, may be null.
4913      * @param searchStrs the CharSequences to search for, may be null.
4914      * @return the last index of any of the CharSequences, -1 if no match.
4915      * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
4916      */
4917     public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
4918         if (str == null || searchStrs == null) {
4919             return INDEX_NOT_FOUND;
4920         }
4921         int ret = INDEX_NOT_FOUND;
4922         int tmp;
4923         for (final CharSequence search : searchStrs) {
4924             if (search == null) {
4925                 continue;
4926             }
4927             tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
4928             if (tmp > ret) {
4929                 ret = tmp;
4930             }
4931         }
4932         return ret;
4933     }
4934 
4935     /**
4936      * Case in-sensitive find of the last index within a CharSequence.
4937      *
4938      * <p>
4939      * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4940      * the start position is negative. A start position greater than the string length searches the whole string.
4941      * </p>
4942      *
4943      * <pre>
4944      * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
4945      * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
4946      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
4947      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
4948      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
4949      * </pre>
4950      *
4951      * @param str       the CharSequence to check, may be null.
4952      * @param searchStr the CharSequence to find, may be null.
4953      * @return the first index of the search CharSequence, -1 if no match or {@code null} string input.
4954      * @since 2.5
4955      * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
4956      * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence) Strings.CI.lastIndexOf(CharSequence, CharSequence)}
4957      */
4958     @Deprecated
4959     public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
4960         return Strings.CI.lastIndexOf(str, searchStr);
4961     }
4962 
4963     /**
4964      * Case in-sensitive find of the last index within a CharSequence from the specified position.
4965      *
4966      * <p>
4967      * A {@code null} CharSequence will return {@code -1}. A negative start position returns {@code -1}. An empty ("") search CharSequence always matches unless
4968      * the start position is negative. A start position greater than the string length searches the whole string. The search starts at the startPos and works
4969      * backwards; matches starting after the start position are ignored.
4970      * </p>
4971      *
4972      * <pre>
4973      * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
4974      * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
4975      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
4976      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
4977      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
4978      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
4979      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
4980      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
4981      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
4982      * </pre>
4983      *
4984      * @param str       the CharSequence to check, may be null.
4985      * @param searchStr the CharSequence to find, may be null.
4986      * @param startPos  the start position.
4987      * @return the last index of the search CharSequence (always &le; startPos), -1 if no match or {@code null} input.
4988      * @since 2.5
4989      * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
4990      * @deprecated Use {@link Strings#lastIndexOf(CharSequence, CharSequence, int) Strings.CI.lastIndexOf(CharSequence, CharSequence, int)}
4991      */
4992     @Deprecated
4993     public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, final int startPos) {
4994         return Strings.CI.lastIndexOf(str, searchStr, startPos);
4995     }
4996 
4997     /**
4998      * Finds the n-th last index within a String, handling {@code null}. This method uses {@link String#lastIndexOf(String)}.
4999      *
5000      * <p>
5001      * A {@code null} String will return {@code -1}.
5002      * </p>
5003      *
5004      * <pre>
5005      * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5006      * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5007      * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5008      * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5009      * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5010      * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5011      * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5012      * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5013      * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5014      * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5015      * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5016      * </pre>
5017      *
5018      * <p>
5019      * Note that 'tail(CharSequence str, int n)' may be implemented as:
5020      * </p>
5021      *
5022      * <pre>
5023      * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5024      * </pre>
5025      *
5026      * @param str       the CharSequence to check, may be null.
5027      * @param searchStr the CharSequence to find, may be null.
5028      * @param ordinal   the n-th last {@code searchStr} to find.
5029      * @return the n-th last index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5030      * @since 2.5
5031      * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5032      */
5033     public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5034         return ordinalIndexOf(str, searchStr, ordinal, true);
5035     }
5036 
5037     /**
5038      * Gets the leftmost {@code len} characters of a String.
5039      *
5040      * <p>
5041      * If {@code len} characters are not available, or the String is {@code null}, the String will be returned without an exception. An empty String is returned
5042      * if len is negative.
5043      * </p>
5044      *
5045      * <pre>
5046      * StringUtils.left(null, *)    = null
5047      * StringUtils.left(*, -ve)     = ""
5048      * StringUtils.left("", *)      = ""
5049      * StringUtils.left("abc", 0)   = ""
5050      * StringUtils.left("abc", 2)   = "ab"
5051      * StringUtils.left("abc", 4)   = "abc"
5052      * </pre>
5053      *
5054      * @param str the String to get the leftmost characters from, may be null.
5055      * @param len the length of the required String.
5056      * @return the leftmost characters, {@code null} if null String input.
5057      */
5058     public static String left(final String str, final int len) {
5059         if (str == null) {
5060             return null;
5061         }
5062         if (len < 0) {
5063             return EMPTY;
5064         }
5065         if (str.length() <= len) {
5066             return str;
5067         }
5068         return str.substring(0, len);
5069     }
5070 
5071     /**
5072      * Left pad a String with spaces (' ').
5073      *
5074      * <p>
5075      * The String is padded to the size of {@code size}.
5076      * </p>
5077      *
5078      * <pre>
5079      * StringUtils.leftPad(null, *)   = null
5080      * StringUtils.leftPad("", 3)     = "   "
5081      * StringUtils.leftPad("bat", 3)  = "bat"
5082      * StringUtils.leftPad("bat", 5)  = "  bat"
5083      * StringUtils.leftPad("bat", 1)  = "bat"
5084      * StringUtils.leftPad("bat", -1) = "bat"
5085      * </pre>
5086      *
5087      * @param str  the String to pad out, may be null.
5088      * @param size the size to pad to.
5089      * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5090      */
5091     public static String leftPad(final String str, final int size) {
5092         return leftPad(str, size, ' ');
5093     }
5094 
5095     /**
5096      * Left pad a String with a specified character.
5097      *
5098      * <p>
5099      * Pad to a size of {@code size}.
5100      * </p>
5101      *
5102      * <pre>
5103      * StringUtils.leftPad(null, *, *)     = null
5104      * StringUtils.leftPad("", 3, 'z')     = "zzz"
5105      * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5106      * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5107      * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5108      * StringUtils.leftPad("bat", -1, 'z') = "bat"
5109      * </pre>
5110      *
5111      * @param str     the String to pad out, may be null.
5112      * @param size    the size to pad to.
5113      * @param padChar the character to pad with.
5114      * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5115      * @since 2.0
5116      */
5117     public static String leftPad(final String str, final int size, final char padChar) {
5118         if (str == null) {
5119             return null;
5120         }
5121         final int pads = size - str.length();
5122         if (pads <= 0) {
5123             return str; // returns original String when possible
5124         }
5125         if (pads > PAD_LIMIT) {
5126             return leftPad(str, size, String.valueOf(padChar));
5127         }
5128         return repeat(padChar, pads).concat(str);
5129     }
5130 
5131     /**
5132      * Left pad a String with a specified String.
5133      *
5134      * <p>
5135      * Pad to a size of {@code size}.
5136      * </p>
5137      *
5138      * <pre>
5139      * StringUtils.leftPad(null, *, *)      = null
5140      * StringUtils.leftPad("", 3, "z")      = "zzz"
5141      * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5142      * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5143      * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5144      * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5145      * StringUtils.leftPad("bat", -1, "yz") = "bat"
5146      * StringUtils.leftPad("bat", 5, null)  = "  bat"
5147      * StringUtils.leftPad("bat", 5, "")    = "  bat"
5148      * </pre>
5149      *
5150      * @param str    the String to pad out, may be null.
5151      * @param size   the size to pad to.
5152      * @param padStr the String to pad with, null or empty treated as single space.
5153      * @return left padded String or original String if no padding is necessary, {@code null} if null String input.
5154      */
5155     public static String leftPad(final String str, final int size, String padStr) {
5156         if (str == null) {
5157             return null;
5158         }
5159         if (isEmpty(padStr)) {
5160             padStr = SPACE;
5161         }
5162         final int padLen = padStr.length();
5163         final int strLen = str.length();
5164         final int pads = size - strLen;
5165         if (pads <= 0) {
5166             return str; // returns original String when possible
5167         }
5168         if (padLen == 1 && pads <= PAD_LIMIT) {
5169             return leftPad(str, size, padStr.charAt(0));
5170         }
5171         if (pads == padLen) {
5172             return padStr.concat(str);
5173         }
5174         if (pads < padLen) {
5175             return padStr.substring(0, pads).concat(str);
5176         }
5177         final char[] padding = new char[pads];
5178         final char[] padChars = padStr.toCharArray();
5179         for (int i = 0; i < pads; i++) {
5180             padding[i] = padChars[i % padLen];
5181         }
5182         return new String(padding).concat(str);
5183     }
5184 
5185     /**
5186      * Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}.
5187      *
5188      * @param cs a CharSequence or {@code null}.
5189      * @return CharSequence length or {@code 0} if the CharSequence is {@code null}.
5190      * @since 2.4
5191      * @since 3.0 Changed signature from length(String) to length(CharSequence)
5192      */
5193     public static int length(final CharSequence cs) {
5194         return cs == null ? 0 : cs.length();
5195     }
5196 
5197     /**
5198      * Converts a String to lower case as per {@link String#toLowerCase()}.
5199      *
5200      * <p>
5201      * A {@code null} input String returns {@code null}.
5202      * </p>
5203      *
5204      * <pre>
5205      * StringUtils.lowerCase(null)  = null
5206      * StringUtils.lowerCase("")    = ""
5207      * StringUtils.lowerCase("aBc") = "abc"
5208      * </pre>
5209      *
5210      * <p>
5211      * <strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()}, the result of this method is affected by the current locale.
5212      * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} should be used with a specific locale (e.g.
5213      * {@link Locale#ENGLISH}).
5214      * </p>
5215      *
5216      * @param str the String to lower case, may be null.
5217      * @return the lower cased String, {@code null} if null String input.
5218      */
5219     public static String lowerCase(final String str) {
5220         if (str == null) {
5221             return null;
5222         }
5223         return str.toLowerCase();
5224     }
5225 
5226     /**
5227      * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5228      *
5229      * <p>
5230      * A {@code null} input String returns {@code null}.
5231      * </p>
5232      *
5233      * <pre>
5234      * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5235      * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5236      * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5237      * </pre>
5238      *
5239      * @param str    the String to lower case, may be null.
5240      * @param locale the locale that defines the case transformation rules, must not be null.
5241      * @return the lower cased String, {@code null} if null String input.
5242      * @since 2.5
5243      */
5244     public static String lowerCase(final String str, final Locale locale) {
5245         if (str == null) {
5246             return null;
5247         }
5248         return str.toLowerCase(LocaleUtils.toLocale(locale));
5249     }
5250 
5251     private static int[] matches(final CharSequence first, final CharSequence second) {
5252         final CharSequence max;
5253         final CharSequence min;
5254         if (first.length() > second.length()) {
5255             max = first;
5256             min = second;
5257         } else {
5258             max = second;
5259             min = first;
5260         }
5261         final int range = Math.max(max.length() / 2 - 1, 0);
5262         final int[] matchIndexes = ArrayFill.fill(new int[min.length()], -1);
5263         final boolean[] matchFlags = new boolean[max.length()];
5264         int matches = 0;
5265         for (int mi = 0; mi < min.length(); mi++) {
5266             final char c1 = min.charAt(mi);
5267             for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5268                 if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5269                     matchIndexes[mi] = xi;
5270                     matchFlags[xi] = true;
5271                     matches++;
5272                     break;
5273                 }
5274             }
5275         }
5276         final char[] ms1 = new char[matches];
5277         final char[] ms2 = new char[matches];
5278         for (int i = 0, si = 0; i < min.length(); i++) {
5279             if (matchIndexes[i] != -1) {
5280                 ms1[si] = min.charAt(i);
5281                 si++;
5282             }
5283         }
5284         for (int i = 0, si = 0; i < max.length(); i++) {
5285             if (matchFlags[i]) {
5286                 ms2[si] = max.charAt(i);
5287                 si++;
5288             }
5289         }
5290         int transpositions = 0;
5291         for (int mi = 0; mi < ms1.length; mi++) {
5292             if (ms1[mi] != ms2[mi]) {
5293                 transpositions++;
5294             }
5295         }
5296         int prefix = 0;
5297         for (int mi = 0; mi < min.length(); mi++) {
5298             if (first.charAt(mi) != second.charAt(mi)) {
5299                 break;
5300             }
5301             prefix++;
5302         }
5303         return new int[] { matches, transpositions / 2, prefix, max.length() };
5304     }
5305 
5306     /**
5307      * Gets {@code len} characters from the middle of a String.
5308      *
5309      * <p>
5310      * If {@code len} characters are not available, the remainder of the String will be returned without an exception. If the String is {@code null},
5311      * {@code null} will be returned. An empty String is returned if len is negative or exceeds the length of {@code str}.
5312      * </p>
5313      *
5314      * <pre>
5315      * StringUtils.mid(null, *, *)    = null
5316      * StringUtils.mid(*, *, -ve)     = ""
5317      * StringUtils.mid("", 0, *)      = ""
5318      * StringUtils.mid("abc", 0, 2)   = "ab"
5319      * StringUtils.mid("abc", 0, 4)   = "abc"
5320      * StringUtils.mid("abc", 2, 4)   = "c"
5321      * StringUtils.mid("abc", 4, 2)   = ""
5322      * StringUtils.mid("abc", -2, 2)  = "ab"
5323      * </pre>
5324      *
5325      * @param str the String to get the characters from, may be null.
5326      * @param pos the position to start from, negative treated as zero.
5327      * @param len the length of the required String.
5328      * @return the middle characters, {@code null} if null String input.
5329      */
5330     public static String mid(final String str, int pos, final int len) {
5331         if (str == null) {
5332             return null;
5333         }
5334         if (len < 0 || pos > str.length()) {
5335             return EMPTY;
5336         }
5337         if (pos < 0) {
5338             pos = 0;
5339         }
5340         if (str.length() <= pos + len) {
5341             return str.substring(pos);
5342         }
5343         return str.substring(pos, pos + len);
5344     }
5345 
5346     /**
5347      * Similar to <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize -space</a>
5348      *
5349      * <p>
5350      * The function returns the argument string with whitespace normalized by using {@code {@link #trim(String)}} to remove leading and trailing whitespace and
5351      * then replacing sequences of whitespace characters by a single space.
5352      * </p>
5353      * In XML Whitespace characters are the same as those allowed by the <a href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 |
5354      * #x9 | #xD | #xA)+
5355      * <p>
5356      * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5357      * </p>
5358      * <p>
5359      * For reference:
5360      * </p>
5361      * <ul>
5362      * <li>\x0B = vertical tab</li>
5363      * <li>\f = #xC = form feed</li>
5364      * <li>#x20 = space</li>
5365      * <li>#x9 = \t</li>
5366      * <li>#xA = \n</li>
5367      * <li>#xD = \r</li>
5368      * </ul>
5369      *
5370      * <p>
5371      * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also normalize. Additionally {@code {@link
5372      * #trim(String)}} removes control characters (char &lt;= 32) from both ends of this String.
5373      * </p>
5374      *
5375      * @param str the source String to normalize whitespaces from, may be null.
5376      * @return the modified string with whitespace normalized, {@code null} if null String input.
5377      * @see Pattern
5378      * @see #trim(String)
5379      * @see <a href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5380      * @since 3.0
5381      */
5382     public static String normalizeSpace(final String str) {
5383         // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5384         // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5385         if (isEmpty(str)) {
5386             return str;
5387         }
5388         final int size = str.length();
5389         final char[] newChars = new char[size];
5390         int count = 0;
5391         int whitespacesCount = 0;
5392         boolean startWhitespaces = true;
5393         for (int i = 0; i < size; i++) {
5394             final char actualChar = str.charAt(i);
5395             final boolean isWhitespace = Character.isWhitespace(actualChar);
5396             if (isWhitespace) {
5397                 if (whitespacesCount == 0 && !startWhitespaces) {
5398                     newChars[count++] = SPACE.charAt(0);
5399                 }
5400                 whitespacesCount++;
5401             } else {
5402                 startWhitespaces = false;
5403                 newChars[count++] = actualChar == 160 ? 32 : actualChar;
5404                 whitespacesCount = 0;
5405             }
5406         }
5407         if (startWhitespaces) {
5408             return EMPTY;
5409         }
5410         return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5411     }
5412 
5413     /**
5414      * Finds the n-th index within a CharSequence, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5415      * <p>
5416      * <strong>Note:</strong> The code starts looking for a match at the start of the target, incrementing the starting index by one after each successful match
5417      * (unless {@code searchStr} is an empty string in which case the position is never incremented and {@code 0} is returned immediately). This means that
5418      * matches may overlap.
5419      * </p>
5420      * <p>
5421      * A {@code null} CharSequence will return {@code -1}.
5422      * </p>
5423      *
5424      * <pre>
5425      * StringUtils.ordinalIndexOf(null, *, *)          = -1
5426      * StringUtils.ordinalIndexOf(*, null, *)          = -1
5427      * StringUtils.ordinalIndexOf("", "", *)           = 0
5428      * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5429      * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5430      * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5431      * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5432      * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5433      * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5434      * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5435      * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5436      * </pre>
5437      *
5438      * <p>
5439      * Matches may overlap:
5440      * </p>
5441      *
5442      * <pre>
5443      * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5444      * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5445      * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5446      *
5447      * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5448      * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5449      * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5450      * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5451      * </pre>
5452      *
5453      * <p>
5454      * Note that 'head(CharSequence str, int n)' may be implemented as:
5455      * </p>
5456      *
5457      * <pre>
5458      * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5459      * </pre>
5460      *
5461      * @param str       the CharSequence to check, may be null.
5462      * @param searchStr the CharSequence to find, may be null.
5463      * @param ordinal   the n-th {@code searchStr} to find.
5464      * @return the n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5465      * @since 2.1
5466      * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5467      */
5468     public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5469         return ordinalIndexOf(str, searchStr, ordinal, false);
5470     }
5471 
5472     /**
5473      * Finds the n-th index within a String, handling {@code null}. This method uses {@link String#indexOf(String)} if possible.
5474      * <p>
5475      * Note that matches may overlap
5476      * <p>
5477      *
5478      * <p>
5479      * A {@code null} CharSequence will return {@code -1}.
5480      * </p>
5481      *
5482      * @param str       the CharSequence to check, may be null.
5483      * @param searchStr the CharSequence to find, may be null.
5484      * @param ordinal   the n-th {@code searchStr} to find, overlapping matches are allowed.
5485      * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf().
5486      * @return the n-th index of the search CharSequence, {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input.
5487      */
5488     // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5489     private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5490         if (str == null || searchStr == null || ordinal <= 0) {
5491             return INDEX_NOT_FOUND;
5492         }
5493         if (searchStr.length() == 0) {
5494             return lastIndex ? str.length() : 0;
5495         }
5496         int found = 0;
5497         // set the initial index beyond the end of the string
5498         // this is to allow for the initial index decrement/increment
5499         int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5500         do {
5501             if (lastIndex) {
5502                 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5503             } else {
5504                 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5505             }
5506             if (index < 0) {
5507                 return index;
5508             }
5509             found++;
5510         } while (found < ordinal);
5511         return index;
5512     }
5513 
5514     /**
5515      * Overlays part of a String with another String.
5516      *
5517      * <p>
5518      * A {@code null} string input returns {@code null}. A negative index is treated as zero. An index greater than the string length is treated as the string
5519      * length. The start index is always the smaller of the two indices.
5520      * </p>
5521      *
5522      * <pre>
5523      * StringUtils.overlay(null, *, *, *)            = null
5524      * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5525      * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5526      * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5527      * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5528      * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5529      * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5530      * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5531      * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5532      * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5533      * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5534      * </pre>
5535      *
5536      * @param str     the String to do overlaying in, may be null.
5537      * @param overlay the String to overlay, may be null.
5538      * @param start   the position to start overlaying at.
5539      * @param end     the position to stop overlaying before.
5540      * @return overlayed String, {@code null} if null String input.
5541      * @since 2.0
5542      */
5543     public static String overlay(final String str, String overlay, int start, int end) {
5544         if (str == null) {
5545             return null;
5546         }
5547         if (overlay == null) {
5548             overlay = EMPTY;
5549         }
5550         final int len = str.length();
5551         if (start < 0) {
5552             start = 0;
5553         }
5554         if (start > len) {
5555             start = len;
5556         }
5557         if (end < 0) {
5558             end = 0;
5559         }
5560         if (end > len) {
5561             end = len;
5562         }
5563         if (start > end) {
5564             final int temp = start;
5565             start = end;
5566             end = temp;
5567         }
5568         return str.substring(0, start) + overlay + str.substring(end);
5569     }
5570 
5571     /**
5572      * Prepends the prefix to the start of the string if the string does not already start with any of the prefixes.
5573      *
5574      * <pre>
5575      * StringUtils.prependIfMissing(null, null) = null
5576      * StringUtils.prependIfMissing("abc", null) = "abc"
5577      * StringUtils.prependIfMissing("", "xyz") = "xyz"
5578      * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5579      * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5580      * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5581      * </pre>
5582      * <p>
5583      * With additional prefixes,
5584      * </p>
5585      *
5586      * <pre>
5587      * StringUtils.prependIfMissing(null, null, null) = null
5588      * StringUtils.prependIfMissing("abc", null, null) = "abc"
5589      * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5590      * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5591      * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5592      * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5593      * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5594      * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5595      * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5596      * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5597      * </pre>
5598      *
5599      * @param str      The string.
5600      * @param prefix   The prefix to prepend to the start of the string.
5601      * @param prefixes Additional prefixes that are valid.
5602      * @return A new String if prefix was prepended, the same string otherwise.
5603      * @since 3.2
5604      * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CS.prependIfMissing(String, CharSequence,
5605      *             CharSequence...)}
5606      */
5607     @Deprecated
5608     public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5609         return Strings.CS.prependIfMissing(str, prefix, prefixes);
5610     }
5611 
5612     /**
5613      * Prepends the prefix to the start of the string if the string does not already start, case-insensitive, with any of the prefixes.
5614      *
5615      * <pre>
5616      * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5617      * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5618      * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5619      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5620      * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5621      * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5622      * </pre>
5623      * <p>
5624      * With additional prefixes,
5625      * </p>
5626      *
5627      * <pre>
5628      * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5629      * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5630      * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5631      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5632      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5633      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5634      * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5635      * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5636      * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5637      * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5638      * </pre>
5639      *
5640      * @param str      The string.
5641      * @param prefix   The prefix to prepend to the start of the string.
5642      * @param prefixes Additional prefixes that are valid (optional).
5643      * @return A new String if prefix was prepended, the same string otherwise.
5644      * @since 3.2
5645      * @deprecated Use {@link Strings#prependIfMissing(String, CharSequence, CharSequence...) Strings.CI.prependIfMissing(String, CharSequence,
5646      *             CharSequence...)}
5647      */
5648     @Deprecated
5649     public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5650         return Strings.CI.prependIfMissing(str, prefix, prefixes);
5651     }
5652 
5653     /**
5654      * Removes all occurrences of a character from within the source string.
5655      *
5656      * <p>
5657      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string.
5658      * </p>
5659      *
5660      * <pre>
5661      * StringUtils.remove(null, *)       = null
5662      * StringUtils.remove("", *)         = ""
5663      * StringUtils.remove("queued", 'u') = "qeed"
5664      * StringUtils.remove("queued", 'z') = "queued"
5665      * </pre>
5666      *
5667      * @param str    the source String to search, may be null.
5668      * @param remove the char to search for and remove, may be null.
5669      * @return the substring with the char removed if found, {@code null} if null String input.
5670      * @since 2.1
5671      */
5672     public static String remove(final String str, final char remove) {
5673         if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5674             return str;
5675         }
5676         final char[] chars = str.toCharArray();
5677         int pos = 0;
5678         for (int i = 0; i < chars.length; i++) {
5679             if (chars[i] != remove) {
5680                 chars[pos++] = chars[i];
5681             }
5682         }
5683         return new String(chars, 0, pos);
5684     }
5685 
5686     /**
5687      * Removes all occurrences of a substring from within the source string.
5688      *
5689      * <p>
5690      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} remove string will return
5691      * the source string. An empty ("") remove string will return the source string.
5692      * </p>
5693      *
5694      * <pre>
5695      * StringUtils.remove(null, *)        = null
5696      * StringUtils.remove("", *)          = ""
5697      * StringUtils.remove(*, null)        = *
5698      * StringUtils.remove(*, "")          = *
5699      * StringUtils.remove("queued", "ue") = "qd"
5700      * StringUtils.remove("queued", "zz") = "queued"
5701      * </pre>
5702      *
5703      * @param str    the source String to search, may be null.
5704      * @param remove the String to search for and remove, may be null.
5705      * @return the substring with the string removed if found, {@code null} if null String input.
5706      * @since 2.1
5707      * @deprecated Use {@link Strings#remove(String, String) Strings.CS.remove(String, String)}
5708      */
5709     @Deprecated
5710     public static String remove(final String str, final String remove) {
5711         return Strings.CS.remove(str, remove);
5712     }
5713 
5714     /**
5715      * Removes each substring of the text String that matches the given regular expression.
5716      *
5717      * This method is a {@code null} safe equivalent to:
5718      * <ul>
5719      * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5720      * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5721      * </ul>
5722      *
5723      * <p>
5724      * A {@code null} reference passed to this method is a no-op.
5725      * </p>
5726      *
5727      * <p>
5728      * Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option
5729      * prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
5730      * </p>
5731      *
5732      * <pre>{@code
5733      * StringUtils.removeAll(null, *)      = null
5734      * StringUtils.removeAll("any", (String) null)  = "any"
5735      * StringUtils.removeAll("any", "")    = "any"
5736      * StringUtils.removeAll("any", ".*")  = ""
5737      * StringUtils.removeAll("any", ".+")  = ""
5738      * StringUtils.removeAll("abc", ".?")  = ""
5739      * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
5740      * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5741      * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5742      * }</pre>
5743      *
5744      * @param text  text to remove from, may be null.
5745      * @param regex the regular expression to which this string is to be matched.
5746      * @return the text with any removes processed, {@code null} if null String input.
5747      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
5748      * @see #replaceAll(String, String, String)
5749      * @see #removePattern(String, String)
5750      * @see String#replaceAll(String, String)
5751      * @see java.util.regex.Pattern
5752      * @see java.util.regex.Pattern#DOTALL
5753      * @since 3.5
5754      * @deprecated Moved to RegExUtils.
5755      */
5756     @Deprecated
5757     public static String removeAll(final String text, final String regex) {
5758         return RegExUtils.removeAll(text, regex);
5759     }
5760 
5761     /**
5762      * Removes a substring only if it is at the end of a source string, otherwise returns the source string.
5763      *
5764      * <p>
5765      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5766      * the source string.
5767      * </p>
5768      *
5769      * <pre>
5770      * StringUtils.removeEnd(null, *)      = null
5771      * StringUtils.removeEnd("", *)        = ""
5772      * StringUtils.removeEnd(*, null)      = *
5773      * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5774      * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5775      * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5776      * StringUtils.removeEnd("abc", "")    = "abc"
5777      * </pre>
5778      *
5779      * @param str    the source String to search, may be null.
5780      * @param remove the String to search for and remove, may be null.
5781      * @return the substring with the string removed if found, {@code null} if null String input.
5782      * @since 2.1
5783      * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CS.removeEnd(String, CharSequence)}
5784      */
5785     @Deprecated
5786     public static String removeEnd(final String str, final String remove) {
5787         return Strings.CS.removeEnd(str, remove);
5788     }
5789 
5790     /**
5791      * Case-insensitive removal of a substring if it is at the end of a source string, otherwise returns the source string.
5792      *
5793      * <p>
5794      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5795      * the source string.
5796      * </p>
5797      *
5798      * <pre>
5799      * StringUtils.removeEndIgnoreCase(null, *)      = null
5800      * StringUtils.removeEndIgnoreCase("", *)        = ""
5801      * StringUtils.removeEndIgnoreCase(*, null)      = *
5802      * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5803      * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5804      * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5805      * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5806      * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5807      * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5808      * </pre>
5809      *
5810      * @param str    the source String to search, may be null.
5811      * @param remove the String to search for (case-insensitive) and remove, may be null.
5812      * @return the substring with the string removed if found, {@code null} if null String input.
5813      * @since 2.4
5814      * @deprecated Use {@link Strings#removeEnd(String, CharSequence) Strings.CI.removeEnd(String, CharSequence)}
5815      */
5816     @Deprecated
5817     public static String removeEndIgnoreCase(final String str, final String remove) {
5818         return Strings.CI.removeEnd(str, remove);
5819     }
5820 
5821     /**
5822      * Removes the first substring of the text string that matches the given regular expression.
5823      *
5824      * This method is a {@code null} safe equivalent to:
5825      * <ul>
5826      * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5827      * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5828      * </ul>
5829      *
5830      * <p>
5831      * A {@code null} reference passed to this method is a no-op.
5832      * </p>
5833      *
5834      * <p>
5835      * The {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as
5836      * single-line mode in Perl.
5837      * </p>
5838      *
5839      * <pre>{@code
5840      * StringUtils.removeFirst(null, *)      = null
5841      * StringUtils.removeFirst("any", (String) null)  = "any"
5842      * StringUtils.removeFirst("any", "")    = "any"
5843      * StringUtils.removeFirst("any", ".*")  = ""
5844      * StringUtils.removeFirst("any", ".+")  = ""
5845      * StringUtils.removeFirst("abc", ".?")  = "bc"
5846      * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
5847      * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
5848      * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5849      * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5850      * }</pre>
5851      *
5852      * @param text  text to remove from, may be null.
5853      * @param regex the regular expression to which this string is to be matched.
5854      * @return the text with the first replacement processed, {@code null} if null String input.
5855      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
5856      * @see #replaceFirst(String, String, String)
5857      * @see String#replaceFirst(String, String)
5858      * @see java.util.regex.Pattern
5859      * @see java.util.regex.Pattern#DOTALL
5860      * @since 3.5
5861      * @deprecated Moved to RegExUtils.
5862      */
5863     @Deprecated
5864     public static String removeFirst(final String text, final String regex) {
5865         return replaceFirst(text, regex, EMPTY);
5866     }
5867 
5868     /**
5869      * Case-insensitive removal of all occurrences of a substring from within the source string.
5870      *
5871      * <p>
5872      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} remove string will return
5873      * the source string. An empty ("") remove string will return the source string.
5874      * </p>
5875      *
5876      * <pre>
5877      * StringUtils.removeIgnoreCase(null, *)        = null
5878      * StringUtils.removeIgnoreCase("", *)          = ""
5879      * StringUtils.removeIgnoreCase(*, null)        = *
5880      * StringUtils.removeIgnoreCase(*, "")          = *
5881      * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
5882      * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
5883      * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
5884      * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
5885      * </pre>
5886      *
5887      * @param str    the source String to search, may be null.
5888      * @param remove the String to search for (case-insensitive) and remove, may be null.
5889      * @return the substring with the string removed if found, {@code null} if null String input.
5890      * @since 3.5
5891      * @deprecated Use {@link Strings#remove(String, String) Strings.CI.remove(String, String)}
5892      */
5893     @Deprecated
5894     public static String removeIgnoreCase(final String str, final String remove) {
5895         return Strings.CI.remove(str, remove);
5896     }
5897 
5898     /**
5899      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5900      *
5901      * This call is a {@code null} safe equivalent to:
5902      * <ul>
5903      * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5904      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5905      * </ul>
5906      *
5907      * <p>
5908      * A {@code null} reference passed to this method is a no-op.
5909      * </p>
5910      *
5911      * <pre>{@code
5912      * StringUtils.removePattern(null, *)       = null
5913      * StringUtils.removePattern("any", (String) null)   = "any"
5914      * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
5915      * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
5916      * }</pre>
5917      *
5918      * @param source the source string.
5919      * @param regex  the regular expression to which this string is to be matched.
5920      * @return The resulting {@link String}.
5921      * @see #replacePattern(String, String, String)
5922      * @see String#replaceAll(String, String)
5923      * @see Pattern#DOTALL
5924      * @since 3.2
5925      * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5926      * @deprecated Moved to RegExUtils.
5927      */
5928     @Deprecated
5929     public static String removePattern(final String source, final String regex) {
5930         return RegExUtils.removePattern(source, regex);
5931     }
5932 
5933     /**
5934      * Removes a char only if it is at the beginning of a source string, otherwise returns the source string.
5935      *
5936      * <p>
5937      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search char will return
5938      * the source string.
5939      * </p>
5940      *
5941      * <pre>
5942      * StringUtils.removeStart(null, *)      = null
5943      * StringUtils.removeStart("", *)        = ""
5944      * StringUtils.removeStart(*, null)      = *
5945      * StringUtils.removeStart("/path", '/') = "path"
5946      * StringUtils.removeStart("path", '/')  = "path"
5947      * StringUtils.removeStart("path", 0)    = "path"
5948      * </pre>
5949      *
5950      * @param str    the source String to search, may be null.
5951      * @param remove the char to search for and remove.
5952      * @return the substring with the char removed if found, {@code null} if null String input.
5953      * @since 3.13.0
5954      */
5955     public static String removeStart(final String str, final char remove) {
5956         if (isEmpty(str)) {
5957             return str;
5958         }
5959         return str.charAt(0) == remove ? str.substring(1) : str;
5960     }
5961 
5962     /**
5963      * Removes a substring only if it is at the beginning of a source string, otherwise returns the source string.
5964      *
5965      * <p>
5966      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5967      * the source string.
5968      * </p>
5969      *
5970      * <pre>
5971      * StringUtils.removeStart(null, *)                    = null
5972      * StringUtils.removeStart("", *)                      = ""
5973      * StringUtils.removeStart(*, null)                    = *
5974      * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
5975      * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
5976      * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
5977      * StringUtils.removeStart("abc", "")                  = "abc"
5978      * </pre>
5979      *
5980      * @param str    the source String to search, may be null.
5981      * @param remove the String to search for and remove, may be null.
5982      * @return the substring with the string removed if found, {@code null} if null String input.
5983      * @since 2.1
5984      * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CS.removeStart(String, CharSequence)}
5985      */
5986     @Deprecated
5987     public static String removeStart(final String str, final String remove) {
5988         return Strings.CS.removeStart(str, remove);
5989     }
5990 
5991     /**
5992      * Case-insensitive removal of a substring if it is at the beginning of a source string, otherwise returns the source string.
5993      *
5994      * <p>
5995      * A {@code null} source string will return {@code null}. An empty ("") source string will return the empty string. A {@code null} search string will return
5996      * the source string.
5997      * </p>
5998      *
5999      * <pre>
6000      * StringUtils.removeStartIgnoreCase(null, *)                    = null
6001      * StringUtils.removeStartIgnoreCase("", *)                      = ""
6002      * StringUtils.removeStartIgnoreCase(*, null)                    = *
6003      * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6004      * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6005      * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6006      * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6007      * StringUtils.removeStartIgnoreCase("abc", "")                  = "abc"
6008      * </pre>
6009      *
6010      * @param str    the source String to search, may be null.
6011      * @param remove the String to search for (case-insensitive) and remove, may be null.
6012      * @return the substring with the string removed if found, {@code null} if null String input.
6013      * @since 2.4
6014      * @deprecated Use {@link Strings#removeStart(String, CharSequence) Strings.CI.removeStart(String, CharSequence)}
6015      */
6016     @Deprecated
6017     public static String removeStartIgnoreCase(final String str, final String remove) {
6018         return Strings.CI.removeStart(str, remove);
6019     }
6020 
6021     /**
6022      * Returns padding using the specified delimiter repeated to a given length.
6023      *
6024      * <pre>
6025      * StringUtils.repeat('e', 0)  = ""
6026      * StringUtils.repeat('e', 3)  = "eee"
6027      * StringUtils.repeat('e', -2) = ""
6028      * </pre>
6029      *
6030      * <p>
6031      * Note: this method does not support padding with <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6032      * as they require a pair of {@code char}s to be represented. If you are needing to support full I18N of your applications consider using
6033      * {@link #repeat(String, int)} instead.
6034      * </p>
6035      *
6036      * @param repeat character to repeat.
6037      * @param count  number of times to repeat char, negative treated as zero.
6038      * @return String with repeated character.
6039      * @see #repeat(String, int)
6040      */
6041     public static String repeat(final char repeat, final int count) {
6042         if (count <= 0) {
6043             return EMPTY;
6044         }
6045         return new String(ArrayFill.fill(new char[count], repeat));
6046     }
6047 
6048     /**
6049      * Repeats a String {@code repeat} times to form a new String.
6050      *
6051      * <pre>
6052      * StringUtils.repeat(null, 2) = null
6053      * StringUtils.repeat("", 0)   = ""
6054      * StringUtils.repeat("", 2)   = ""
6055      * StringUtils.repeat("a", 3)  = "aaa"
6056      * StringUtils.repeat("ab", 2) = "abab"
6057      * StringUtils.repeat("a", -2) = ""
6058      * </pre>
6059      *
6060      * @param repeat the String to repeat, may be null.
6061      * @param count  number of times to repeat str, negative treated as zero.
6062      * @return a new String consisting of the original String repeated, {@code null} if null String input.
6063      */
6064     public static String repeat(final String repeat, final int count) {
6065         // Performance tuned for 2.0 (JDK1.4)
6066         if (repeat == null) {
6067             return null;
6068         }
6069         if (count <= 0) {
6070             return EMPTY;
6071         }
6072         final int inputLength = repeat.length();
6073         if (count == 1 || inputLength == 0) {
6074             return repeat;
6075         }
6076         if (inputLength == 1 && count <= PAD_LIMIT) {
6077             return repeat(repeat.charAt(0), count);
6078         }
6079         final int outputLength = inputLength * count;
6080         switch (inputLength) {
6081         case 1:
6082             return repeat(repeat.charAt(0), count);
6083         case 2:
6084             final char ch0 = repeat.charAt(0);
6085             final char ch1 = repeat.charAt(1);
6086             final char[] output2 = new char[outputLength];
6087             for (int i = count * 2 - 2; i >= 0; i--, i--) {
6088                 output2[i] = ch0;
6089                 output2[i + 1] = ch1;
6090             }
6091             return new String(output2);
6092         default:
6093             final StringBuilder buf = new StringBuilder(outputLength);
6094             for (int i = 0; i < count; i++) {
6095                 buf.append(repeat);
6096             }
6097             return buf.toString();
6098         }
6099     }
6100 
6101     /**
6102      * Repeats a String {@code repeat} times to form a new String, with a String separator injected each time.
6103      *
6104      * <pre>
6105      * StringUtils.repeat(null, null, 2) = null
6106      * StringUtils.repeat(null, "x", 2)  = null
6107      * StringUtils.repeat("", null, 0)   = ""
6108      * StringUtils.repeat("", "", 2)     = ""
6109      * StringUtils.repeat("", "x", 3)    = "xx"
6110      * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6111      * </pre>
6112      *
6113      * @param repeat    the String to repeat, may be null.
6114      * @param separator the String to inject, may be null.
6115      * @param count     number of times to repeat str, negative treated as zero.
6116      * @return a new String consisting of the original String repeated, {@code null} if null String input.
6117      * @since 2.5
6118      */
6119     public static String repeat(final String repeat, final String separator, final int count) {
6120         if (repeat == null || separator == null) {
6121             return repeat(repeat, count);
6122         }
6123         // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6124         final String result = repeat(repeat + separator, count);
6125         return Strings.CS.removeEnd(result, separator);
6126     }
6127 
6128     /**
6129      * Replaces all occurrences of a String within another String.
6130      *
6131      * <p>
6132      * A {@code null} reference passed to this method is a no-op.
6133      * </p>
6134      *
6135      * <pre>
6136      * StringUtils.replace(null, *, *)        = null
6137      * StringUtils.replace("", *, *)          = ""
6138      * StringUtils.replace("any", null, *)    = "any"
6139      * StringUtils.replace("any", *, null)    = "any"
6140      * StringUtils.replace("any", "", *)      = "any"
6141      * StringUtils.replace("aba", "a", null)  = "aba"
6142      * StringUtils.replace("aba", "a", "")    = "b"
6143      * StringUtils.replace("aba", "a", "z")   = "zbz"
6144      * </pre>
6145      *
6146      * @param text         text to search and replace in, may be null.
6147      * @param searchString the String to search for, may be null.
6148      * @param replacement  the String to replace it with, may be null.
6149      * @return the text with any replacements processed, {@code null} if null String input.
6150      * @see #replace(String text, String searchString, String replacement, int max)
6151      * @deprecated Use {@link Strings#replace(String, String, String) Strings.CS.replace(String, String, String)}
6152      */
6153     @Deprecated
6154     public static String replace(final String text, final String searchString, final String replacement) {
6155         return Strings.CS.replace(text, searchString, replacement);
6156     }
6157 
6158     /**
6159      * Replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6160      *
6161      * <p>
6162      * A {@code null} reference passed to this method is a no-op.
6163      * </p>
6164      *
6165      * <pre>
6166      * StringUtils.replace(null, *, *, *)         = null
6167      * StringUtils.replace("", *, *, *)           = ""
6168      * StringUtils.replace("any", null, *, *)     = "any"
6169      * StringUtils.replace("any", *, null, *)     = "any"
6170      * StringUtils.replace("any", "", *, *)       = "any"
6171      * StringUtils.replace("any", *, *, 0)        = "any"
6172      * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6173      * StringUtils.replace("abaa", "a", "", -1)   = "b"
6174      * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6175      * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6176      * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6177      * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6178      * </pre>
6179      *
6180      * @param text         text to search and replace in, may be null.
6181      * @param searchString the String to search for, may be null.
6182      * @param replacement  the String to replace it with, may be null.
6183      * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6184      * @return the text with any replacements processed, {@code null} if null String input.
6185      * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CS.replace(String, String, String, int)}
6186      */
6187     @Deprecated
6188     public static String replace(final String text, final String searchString, final String replacement, final int max) {
6189         return Strings.CS.replace(text, searchString, replacement, max);
6190     }
6191 
6192     /**
6193      * Replaces each substring of the text String that matches the given regular expression with the given replacement.
6194      *
6195      * This method is a {@code null} safe equivalent to:
6196      * <ul>
6197      * <li>{@code text.replaceAll(regex, replacement)}</li>
6198      * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6199      * </ul>
6200      *
6201      * <p>
6202      * A {@code null} reference passed to this method is a no-op.
6203      * </p>
6204      *
6205      * <p>
6206      * Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL
6207      * option prepend {@code "(?s)"} to the regex. DOTALL is also known as single-line mode in Perl.
6208      * </p>
6209      *
6210      * <pre>{@code
6211      * StringUtils.replaceAll(null, *, *)                                         = null
6212      * StringUtils.replaceAll("any", (String) null, *)                            = "any"
6213      * StringUtils.replaceAll("any", *, null)                                     = "any"
6214      * StringUtils.replaceAll("", "", "zzz")                                      = "zzz"
6215      * StringUtils.replaceAll("", ".*", "zzz")                                    = "zzz"
6216      * StringUtils.replaceAll("", ".+", "zzz")                                    = ""
6217      * StringUtils.replaceAll("abc", "", "ZZ")                                    = "ZZaZZbZZcZZ"
6218      * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")                          = "z\nz"
6219      * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")                      = "z"
6220      * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6221      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6222      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6223      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6224      * }</pre>
6225      *
6226      * @param text        text to search and replace in, may be null.
6227      * @param regex       the regular expression to which this string is to be matched.
6228      * @param replacement the string to be substituted for each match.
6229      * @return the text with any replacements processed, {@code null} if null String input.
6230      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
6231      * @see #replacePattern(String, String, String)
6232      * @see String#replaceAll(String, String)
6233      * @see java.util.regex.Pattern
6234      * @see java.util.regex.Pattern#DOTALL
6235      * @since 3.5
6236      * @deprecated Moved to RegExUtils.
6237      */
6238     @Deprecated
6239     public static String replaceAll(final String text, final String regex, final String replacement) {
6240         return RegExUtils.replaceAll(text, regex, replacement);
6241     }
6242 
6243     /**
6244      * Replaces all occurrences of a character in a String with another. This is a null-safe version of {@link String#replace(char, char)}.
6245      *
6246      * <p>
6247      * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string.
6248      * </p>
6249      *
6250      * <pre>
6251      * StringUtils.replaceChars(null, *, *)        = null
6252      * StringUtils.replaceChars("", *, *)          = ""
6253      * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6254      * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6255      * </pre>
6256      *
6257      * @param str         String to replace characters in, may be null.
6258      * @param searchChar  the character to search for, may be null.
6259      * @param replaceChar the character to replace, may be null.
6260      * @return modified String, {@code null} if null string input.
6261      * @since 2.0
6262      */
6263     public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6264         if (str == null) {
6265             return null;
6266         }
6267         return str.replace(searchChar, replaceChar);
6268     }
6269 
6270     /**
6271      * Replaces multiple characters in a String in one go. This method can also be used to delete characters.
6272      *
6273      * <p>
6274      * For example:<br>
6275      * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.
6276      * </p>
6277      *
6278      * <p>
6279      * A {@code null} string input returns {@code null}. An empty ("") string input returns an empty string. A null or empty set of search characters returns
6280      * the input string.
6281      * </p>
6282      *
6283      * <p>
6284      * The length of the search characters should normally equal the length of the replace characters. If the search characters is longer, then the extra search
6285      * characters are deleted. If the search characters is shorter, then the extra replace characters are ignored.
6286      * </p>
6287      *
6288      * <pre>
6289      * StringUtils.replaceChars(null, *, *)           = null
6290      * StringUtils.replaceChars("", *, *)             = ""
6291      * StringUtils.replaceChars("abc", null, *)       = "abc"
6292      * StringUtils.replaceChars("abc", "", *)         = "abc"
6293      * StringUtils.replaceChars("abc", "b", null)     = "ac"
6294      * StringUtils.replaceChars("abc", "b", "")       = "ac"
6295      * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6296      * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6297      * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6298      * </pre>
6299      *
6300      * @param str          String to replace characters in, may be null.
6301      * @param searchChars  a set of characters to search for, may be null.
6302      * @param replaceChars a set of characters to replace, may be null.
6303      * @return modified String, {@code null} if null string input.
6304      * @since 2.0
6305      */
6306     public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6307         if (isEmpty(str) || isEmpty(searchChars)) {
6308             return str;
6309         }
6310         replaceChars = ObjectUtils.toString(replaceChars);
6311         boolean modified = false;
6312         final int replaceCharsLength = replaceChars.length();
6313         final int strLength = str.length();
6314         final StringBuilder buf = new StringBuilder(strLength);
6315         for (int i = 0; i < strLength; i++) {
6316             final char ch = str.charAt(i);
6317             final int index = searchChars.indexOf(ch);
6318             if (index >= 0) {
6319                 modified = true;
6320                 if (index < replaceCharsLength) {
6321                     buf.append(replaceChars.charAt(index));
6322                 }
6323             } else {
6324                 buf.append(ch);
6325             }
6326         }
6327         if (modified) {
6328             return buf.toString();
6329         }
6330         return str;
6331     }
6332 
6333     /**
6334      * Replaces all occurrences of Strings within another String.
6335      *
6336      * <p>
6337      * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored. This
6338      * will not repeat. For repeating replaces, call the overloaded method.
6339      * </p>
6340      *
6341      * <pre>
6342      *  StringUtils.replaceEach(null, *, *)                                                = null
6343      *  StringUtils.replaceEach("", *, *)                                                  = ""
6344      *  StringUtils.replaceEach("aba", null, null)                                         = "aba"
6345      *  StringUtils.replaceEach("aba", new String[0], null)                                = "aba"
6346      *  StringUtils.replaceEach("aba", null, new String[0])                                = "aba"
6347      *  StringUtils.replaceEach("aba", new String[]{"a"}, null)                            = "aba"
6348      *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})                = "b"
6349      *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})              = "aba"
6350      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6351      *  (example of how it does not repeat)
6352      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6353      * </pre>
6354      *
6355      * @param text            text to search and replace in, no-op if null.
6356      * @param searchList      the Strings to search for, no-op if null.
6357      * @param replacementList the Strings to replace them with, no-op if null.
6358      * @return the text with any replacements processed, {@code null} if null String input.
6359      * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
6360      * @since 2.4
6361      */
6362     public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6363         return replaceEach(text, searchList, replacementList, false, 0);
6364     }
6365 
6366     /**
6367      * Replace all occurrences of Strings within another String. This is a private recursive helper method for
6368      * {@link #replaceEachRepeatedly(String, String[], String[])} and {@link #replaceEach(String, String[], String[])}
6369      *
6370      * <p>
6371      * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored.
6372      * </p>
6373      *
6374      * <pre>
6375      *  StringUtils.replaceEach(null, *, *, *, *)                                                     = null
6376      *  StringUtils.replaceEach("", *, *, *, *)                                                       = ""
6377      *  StringUtils.replaceEach("aba", null, null, *, *)                                              = "aba"
6378      *  StringUtils.replaceEach("aba", new String[0], null, *, *)                                     = "aba"
6379      *  StringUtils.replaceEach("aba", null, new String[0], *, *)                                     = "aba"
6380      *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *)                                 = "aba"
6381      *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0)                   = "b"
6382      *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0)                 = "aba"
6383      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0)     = "wcte"
6384      *  (example of how it repeats)
6385      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6386      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2)  = "tcte"
6387      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *)      = IllegalStateException
6388      * </pre>
6389      *
6390      * @param text            text to search and replace in, no-op if null.
6391      * @param searchList      the Strings to search for, no-op if null.
6392      * @param replacementList the Strings to replace them with, no-op if null.
6393      * @param repeat          if true, then replace repeatedly until there are no more possible replacements or timeToLive < 0.
6394      * @param timeToLive      if less than 0 then there is a circular reference and endless loop.
6395      * @return the text with any replacements processed, {@code null} if null String input.
6396      * @throws IllegalStateException    if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
6397      * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
6398      * @since 2.4
6399      */
6400     private static String replaceEach(
6401             final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6402 
6403         // mchyzer Performance note: This creates very few new objects (one major goal)
6404         // let me know if there are performance requests, we can create a harness to measure
6405         if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList)) {
6406             return text;
6407         }
6408 
6409         // if recursing, this shouldn't be less than 0
6410         if (timeToLive < 0) {
6411             throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6412                 "output of one loop is the input of another");
6413         }
6414 
6415         final int searchLength = searchList.length;
6416         final int replacementLength = replacementList.length;
6417 
6418         // make sure lengths are ok, these need to be equal
6419         if (searchLength != replacementLength) {
6420             throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6421                 + searchLength
6422                 + " vs "
6423                 + replacementLength);
6424         }
6425 
6426         // keep track of which still have matches
6427         final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6428 
6429         // index on index that the match was found
6430         int textIndex = -1;
6431         int replaceIndex = -1;
6432         int tempIndex;
6433 
6434         // index of replace array that will replace the search string found
6435         // NOTE: logic duplicated below START
6436         for (int i = 0; i < searchLength; i++) {
6437             if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6438                 continue;
6439             }
6440             tempIndex = text.indexOf(searchList[i]);
6441 
6442             // see if we need to keep searching for this
6443             if (tempIndex == -1) {
6444                 noMoreMatchesForReplIndex[i] = true;
6445             } else if (textIndex == -1 || tempIndex < textIndex) {
6446                 textIndex = tempIndex;
6447                 replaceIndex = i;
6448             }
6449         }
6450         // NOTE: logic mostly below END
6451 
6452         // no search strings found, we are done
6453         if (textIndex == -1) {
6454             return text;
6455         }
6456 
6457         int start = 0;
6458 
6459         // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6460         int increase = 0;
6461 
6462         // count the replacement text elements that are larger than their corresponding text being replaced
6463         for (int i = 0; i < searchList.length; i++) {
6464             if (searchList[i] == null || replacementList[i] == null) {
6465                 continue;
6466             }
6467             final int greater = replacementList[i].length() - searchList[i].length();
6468             if (greater > 0) {
6469                 increase += 3 * greater; // assume 3 matches
6470             }
6471         }
6472         // have upper-bound at 20% increase, then let Java take over
6473         increase = Math.min(increase, text.length() / 5);
6474 
6475         final StringBuilder buf = new StringBuilder(text.length() + increase);
6476 
6477         while (textIndex != -1) {
6478 
6479             for (int i = start; i < textIndex; i++) {
6480                 buf.append(text.charAt(i));
6481             }
6482             buf.append(replacementList[replaceIndex]);
6483 
6484             start = textIndex + searchList[replaceIndex].length();
6485 
6486             textIndex = -1;
6487             replaceIndex = -1;
6488             // find the next earliest match
6489             // NOTE: logic mostly duplicated above START
6490             for (int i = 0; i < searchLength; i++) {
6491                 if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6492                     continue;
6493                 }
6494                 tempIndex = text.indexOf(searchList[i], start);
6495 
6496                 // see if we need to keep searching for this
6497                 if (tempIndex == -1) {
6498                     noMoreMatchesForReplIndex[i] = true;
6499                 } else if (textIndex == -1 || tempIndex < textIndex) {
6500                     textIndex = tempIndex;
6501                     replaceIndex = i;
6502                 }
6503             }
6504             // NOTE: logic duplicated above END
6505 
6506         }
6507         final int textLength = text.length();
6508         for (int i = start; i < textLength; i++) {
6509             buf.append(text.charAt(i));
6510         }
6511         final String result = buf.toString();
6512         if (!repeat) {
6513             return result;
6514         }
6515 
6516         return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6517     }
6518 
6519     /**
6520      * Replaces all occurrences of Strings within another String.
6521      *
6522      * <p>
6523      * A {@code null} reference passed to this method is a no-op, or if any "search string" or "string to replace" is null, that replace will be ignored.
6524      * </p>
6525      *
6526      * <pre>
6527      *  StringUtils.replaceEachRepeatedly(null, *, *)                                                = null
6528      *  StringUtils.replaceEachRepeatedly("", *, *)                                                  = ""
6529      *  StringUtils.replaceEachRepeatedly("aba", null, null)                                         = "aba"
6530      *  StringUtils.replaceEachRepeatedly("aba", new String[0], null)                                = "aba"
6531      *  StringUtils.replaceEachRepeatedly("aba", null, new String[0])                                = "aba"
6532      *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null)                            = "aba"
6533      *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""})                = "b"
6534      *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"})              = "aba"
6535      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6536      *  (example of how it repeats)
6537      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "tcte"
6538      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6539      * </pre>
6540      *
6541      * @param text            text to search and replace in, no-op if null.
6542      * @param searchList      the Strings to search for, no-op if null.
6543      * @param replacementList the Strings to replace them with, no-op if null.
6544      * @return the text with any replacements processed, {@code null} if null String input.
6545      * @throws IllegalStateException    if the search is repeating and there is an endless loop due to outputs of one being inputs to another.
6546      * @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok, and/or size 0).
6547      * @since 2.4
6548      */
6549     public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6550         final int timeToLive = Math.max(ArrayUtils.getLength(searchList), DEFAULT_TTL);
6551         return replaceEach(text, searchList, replacementList, true, timeToLive);
6552     }
6553 
6554     /**
6555      * Replaces the first substring of the text string that matches the given regular expression with the given replacement.
6556      *
6557      * This method is a {@code null} safe equivalent to:
6558      * <ul>
6559      * <li>{@code text.replaceFirst(regex, replacement)}</li>
6560      * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6561      * </ul>
6562      *
6563      * <p>
6564      * A {@code null} reference passed to this method is a no-op.
6565      * </p>
6566      *
6567      * <p>
6568      * The {@link Pattern#DOTALL} option is NOT automatically added. To use the DOTALL option prepend {@code "(?s)"} to the regex. DOTALL is also known as
6569      * single-line mode in Perl.
6570      * </p>
6571      *
6572      * <pre>{@code
6573      * StringUtils.replaceFirst(null, *, *)       = null
6574      * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6575      * StringUtils.replaceFirst("any", *, null)   = "any"
6576      * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6577      * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6578      * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6579      * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6580      * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
6581      * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
6582      * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6583      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6584      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6585      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6586      * }</pre>
6587      *
6588      * @param text        text to search and replace in, may be null.
6589      * @param regex       the regular expression to which this string is to be matched.
6590      * @param replacement the string to be substituted for the first match.
6591      * @return the text with the first replacement processed, {@code null} if null String input.
6592      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid.
6593      * @see String#replaceFirst(String, String)
6594      * @see java.util.regex.Pattern
6595      * @see java.util.regex.Pattern#DOTALL
6596      * @since 3.5
6597      * @deprecated Moved to RegExUtils.
6598      */
6599     @Deprecated
6600     public static String replaceFirst(final String text, final String regex, final String replacement) {
6601         return RegExUtils.replaceFirst(text, regex, replacement);
6602     }
6603 
6604     /**
6605      * Case insensitively replaces all occurrences of a String within another String.
6606      *
6607      * <p>
6608      * A {@code null} reference passed to this method is a no-op.
6609      * </p>
6610      *
6611      * <pre>
6612      * StringUtils.replaceIgnoreCase(null, *, *)        = null
6613      * StringUtils.replaceIgnoreCase("", *, *)          = ""
6614      * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6615      * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6616      * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6617      * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6618      * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6619      * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6620      * </pre>
6621      *
6622      * @param text         text to search and replace in, may be null.
6623      * @param searchString the String to search for (case-insensitive), may be null.
6624      * @param replacement  the String to replace it with, may be null.
6625      * @return the text with any replacements processed, {@code null} if null String input.
6626      * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6627      * @since 3.5
6628      * @deprecated Use {@link Strings#replace(String, String, String) Strings.CI.replace(String, String, String)}
6629      */
6630     @Deprecated
6631     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6632         return Strings.CI.replace(text, searchString, replacement);
6633     }
6634 
6635     /**
6636      * Case insensitively replaces a String with another String inside a larger String, for the first {@code max} values of the search String.
6637      *
6638      * <p>
6639      * A {@code null} reference passed to this method is a no-op.
6640      * </p>
6641      *
6642      * <pre>
6643      * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6644      * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6645      * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6646      * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6647      * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6648      * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6649      * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6650      * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6651      * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6652      * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6653      * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6654      * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6655      * </pre>
6656      *
6657      * @param text         text to search and replace in, may be null.
6658      * @param searchString the String to search for (case-insensitive), may be null.
6659      * @param replacement  the String to replace it with, may be null.
6660      * @param max          maximum number of values to replace, or {@code -1} if no maximum.
6661      * @return the text with any replacements processed, {@code null} if null String input.
6662      * @since 3.5
6663      * @deprecated Use {@link Strings#replace(String, String, String, int) Strings.CI.replace(String, String, String, int)}
6664      */
6665     @Deprecated
6666     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6667         return Strings.CI.replace(text, searchString, replacement, max);
6668     }
6669 
6670     /**
6671      * Replaces a String with another String inside a larger String, once.
6672      *
6673      * <p>
6674      * A {@code null} reference passed to this method is a no-op.
6675      * </p>
6676      *
6677      * <pre>
6678      * StringUtils.replaceOnce(null, *, *)        = null
6679      * StringUtils.replaceOnce("", *, *)          = ""
6680      * StringUtils.replaceOnce("any", null, *)    = "any"
6681      * StringUtils.replaceOnce("any", *, null)    = "any"
6682      * StringUtils.replaceOnce("any", "", *)      = "any"
6683      * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6684      * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6685      * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6686      * </pre>
6687      *
6688      * @param text         text to search and replace in, may be null.
6689      * @param searchString the String to search for, may be null.
6690      * @param replacement  the String to replace with, may be null.
6691      * @return the text with any replacements processed, {@code null} if null String input.
6692      * @see #replace(String text, String searchString, String replacement, int max)
6693      * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CS.replaceOnce(String, String, String)}
6694      */
6695     @Deprecated
6696     public static String replaceOnce(final String text, final String searchString, final String replacement) {
6697         return Strings.CS.replaceOnce(text, searchString, replacement);
6698     }
6699 
6700     /**
6701      * Case insensitively replaces a String with another String inside a larger String, once.
6702      *
6703      * <p>
6704      * A {@code null} reference passed to this method is a no-op.
6705      * </p>
6706      *
6707      * <pre>
6708      * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6709      * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6710      * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6711      * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
6712      * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
6713      * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
6714      * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
6715      * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
6716      * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
6717      * </pre>
6718      *
6719      * @param text         text to search and replace in, may be null.
6720      * @param searchString the String to search for (case-insensitive), may be null.
6721      * @param replacement  the String to replace with, may be null.
6722      * @return the text with any replacements processed, {@code null} if null String input.
6723      * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6724      * @since 3.5
6725      * @deprecated Use {@link Strings#replaceOnce(String, String, String) Strings.CI.replaceOnce(String, String, String)}
6726      */
6727     @Deprecated
6728     public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
6729         return Strings.CI.replaceOnce(text, searchString, replacement);
6730     }
6731 
6732     /**
6733      * Replaces each substring of the source String that matches the given regular expression with the given replacement using the {@link Pattern#DOTALL}
6734      * option. DOTALL is also known as single-line mode in Perl.
6735      *
6736      * This call is a {@code null} safe equivalent to:
6737      * <ul>
6738      * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
6739      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
6740      * </ul>
6741      *
6742      * <p>
6743      * A {@code null} reference passed to this method is a no-op.
6744      * </p>
6745      *
6746      * <pre>{@code
6747      * StringUtils.replacePattern(null, *, *)                                         = null
6748      * StringUtils.replacePattern("any", (String) null, *)                            = "any"
6749      * StringUtils.replacePattern("any", *, null)                                     = "any"
6750      * StringUtils.replacePattern("", "", "zzz")                                      = "zzz"
6751      * StringUtils.replacePattern("", ".*", "zzz")                                    = "zzz"
6752      * StringUtils.replacePattern("", ".+", "zzz")                                    = ""
6753      * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")                          = "z"
6754      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")                          = "ABC___123"
6755      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")                     = "ABC_123"
6756      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")                      = "ABC123"
6757      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6758      * }</pre>
6759      *
6760      * @param source      the source string.
6761      * @param regex       the regular expression to which this string is to be matched.
6762      * @param replacement the string to be substituted for each match.
6763      * @return The resulting {@link String}.
6764      * @see #replaceAll(String, String, String)
6765      * @see String#replaceAll(String, String)
6766      * @see Pattern#DOTALL
6767      * @since 3.2
6768      * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6769      * @deprecated Moved to RegExUtils.
6770      */
6771     @Deprecated
6772     public static String replacePattern(final String source, final String regex, final String replacement) {
6773         return RegExUtils.replacePattern(source, regex, replacement);
6774     }
6775 
6776     /**
6777      * Reverses a String as per {@link StringBuilder#reverse()}.
6778      *
6779      * <p>
6780      * A {@code null} String returns {@code null}.
6781      * </p>
6782      *
6783      * <pre>
6784      * StringUtils.reverse(null)  = null
6785      * StringUtils.reverse("")    = ""
6786      * StringUtils.reverse("bat") = "tab"
6787      * </pre>
6788      *
6789      * @param str the String to reverse, may be null.
6790      * @return the reversed String, {@code null} if null String input.
6791      */
6792     public static String reverse(final String str) {
6793         if (str == null) {
6794             return null;
6795         }
6796         return new StringBuilder(str).reverse().toString();
6797     }
6798 
6799     /**
6800      * Reverses a String that is delimited by a specific character.
6801      *
6802      * <p>
6803      * The Strings between the delimiters are not reversed. Thus java.lang.String becomes String.lang.java (if the delimiter is {@code '.'}).
6804      * </p>
6805      *
6806      * <pre>
6807      * StringUtils.reverseDelimited(null, *)      = null
6808      * StringUtils.reverseDelimited("", *)        = ""
6809      * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
6810      * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
6811      * </pre>
6812      *
6813      * @param str           the String to reverse, may be null.
6814      * @param separatorChar the separator character to use.
6815      * @return the reversed String, {@code null} if null String input.
6816      * @since 2.0
6817      */
6818     public static String reverseDelimited(final String str, final char separatorChar) {
6819         final String[] strs = split(str, separatorChar);
6820         ArrayUtils.reverse(strs);
6821         return join(strs, separatorChar);
6822     }
6823 
6824     /**
6825      * Gets the rightmost {@code len} characters of a String.
6826      *
6827      * <p>
6828      * If {@code len} characters are not available, or the String is {@code null}, the String will be returned without an an exception. An empty String is
6829      * returned if len is negative.
6830      * </p>
6831      *
6832      * <pre>
6833      * StringUtils.right(null, *)    = null
6834      * StringUtils.right(*, -ve)     = ""
6835      * StringUtils.right("", *)      = ""
6836      * StringUtils.right("abc", 0)   = ""
6837      * StringUtils.right("abc", 2)   = "bc"
6838      * StringUtils.right("abc", 4)   = "abc"
6839      * </pre>
6840      *
6841      * @param str the String to get the rightmost characters from, may be null.
6842      * @param len the length of the required String.
6843      * @return the rightmost characters, {@code null} if null String input.
6844      */
6845     public static String right(final String str, final int len) {
6846         if (str == null) {
6847             return null;
6848         }
6849         if (len < 0) {
6850             return EMPTY;
6851         }
6852         if (str.length() <= len) {
6853             return str;
6854         }
6855         return str.substring(str.length() - len);
6856     }
6857 
6858     /**
6859      * Right pad a String with spaces (' ').
6860      *
6861      * <p>
6862      * The String is padded to the size of {@code size}.
6863      * </p>
6864      *
6865      * <pre>
6866      * StringUtils.rightPad(null, *)   = null
6867      * StringUtils.rightPad("", 3)     = "   "
6868      * StringUtils.rightPad("bat", 3)  = "bat"
6869      * StringUtils.rightPad("bat", 5)  = "bat  "
6870      * StringUtils.rightPad("bat", 1)  = "bat"
6871      * StringUtils.rightPad("bat", -1) = "bat"
6872      * </pre>
6873      *
6874      * @param str  the String to pad out, may be null.
6875      * @param size the size to pad to.
6876      * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
6877      */
6878     public static String rightPad(final String str, final int size) {
6879         return rightPad(str, size, ' ');
6880     }
6881 
6882     /**
6883      * Right pad a String with a specified character.
6884      *
6885      * <p>
6886      * The String is padded to the size of {@code size}.
6887      * </p>
6888      *
6889      * <pre>
6890      * StringUtils.rightPad(null, *, *)     = null
6891      * StringUtils.rightPad("", 3, 'z')     = "zzz"
6892      * StringUtils.rightPad("bat", 3, 'z')  = "bat"
6893      * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
6894      * StringUtils.rightPad("bat", 1, 'z')  = "bat"
6895      * StringUtils.rightPad("bat", -1, 'z') = "bat"
6896      * </pre>
6897      *
6898      * @param str     the String to pad out, may be null.
6899      * @param size    the size to pad to.
6900      * @param padChar the character to pad with.
6901      * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
6902      * @since 2.0
6903      */
6904     public static String rightPad(final String str, final int size, final char padChar) {
6905         if (str == null) {
6906             return null;
6907         }
6908         final int pads = size - str.length();
6909         if (pads <= 0) {
6910             return str; // returns original String when possible
6911         }
6912         if (pads > PAD_LIMIT) {
6913             return rightPad(str, size, String.valueOf(padChar));
6914         }
6915         return str.concat(repeat(padChar, pads));
6916     }
6917 
6918     /**
6919      * Right pad a String with a specified String.
6920      *
6921      * <p>
6922      * The String is padded to the size of {@code size}.
6923      * </p>
6924      *
6925      * <pre>
6926      * StringUtils.rightPad(null, *, *)      = null
6927      * StringUtils.rightPad("", 3, "z")      = "zzz"
6928      * StringUtils.rightPad("bat", 3, "yz")  = "bat"
6929      * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
6930      * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
6931      * StringUtils.rightPad("bat", 1, "yz")  = "bat"
6932      * StringUtils.rightPad("bat", -1, "yz") = "bat"
6933      * StringUtils.rightPad("bat", 5, null)  = "bat  "
6934      * StringUtils.rightPad("bat", 5, "")    = "bat  "
6935      * </pre>
6936      *
6937      * @param str    the String to pad out, may be null.
6938      * @param size   the size to pad to.
6939      * @param padStr the String to pad with, null or empty treated as single space.
6940      * @return right padded String or original String if no padding is necessary, {@code null} if null String input.
6941      */
6942     public static String rightPad(final String str, final int size, String padStr) {
6943         if (str == null) {
6944             return null;
6945         }
6946         if (isEmpty(padStr)) {
6947             padStr = SPACE;
6948         }
6949         final int padLen = padStr.length();
6950         final int strLen = str.length();
6951         final int pads = size - strLen;
6952         if (pads <= 0) {
6953             return str; // returns original String when possible
6954         }
6955         if (padLen == 1 && pads <= PAD_LIMIT) {
6956             return rightPad(str, size, padStr.charAt(0));
6957         }
6958         if (pads == padLen) {
6959             return str.concat(padStr);
6960         }
6961         if (pads < padLen) {
6962             return str.concat(padStr.substring(0, pads));
6963         }
6964         final char[] padding = new char[pads];
6965         final char[] padChars = padStr.toCharArray();
6966         for (int i = 0; i < pads; i++) {
6967             padding[i] = padChars[i % padLen];
6968         }
6969         return str.concat(new String(padding));
6970     }
6971 
6972     /**
6973      * Rotate (circular shift) a String of {@code shift} characters.
6974      * <ul>
6975      * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
6976      * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
6977      * </ul>
6978      *
6979      * <pre>
6980      * StringUtils.rotate(null, *)        = null
6981      * StringUtils.rotate("", *)          = ""
6982      * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
6983      * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
6984      * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
6985      * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
6986      * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
6987      * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
6988      * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
6989      * </pre>
6990      *
6991      * @param str   the String to rotate, may be null.
6992      * @param shift number of time to shift (positive : right shift, negative : left shift).
6993      * @return the rotated String, or the original String if {@code shift == 0}, or {@code null} if null String input.
6994      * @since 3.5
6995      */
6996     public static String rotate(final String str, final int shift) {
6997         if (str == null) {
6998             return null;
6999         }
7000         final int strLen = str.length();
7001         if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7002             return str;
7003         }
7004         final StringBuilder builder = new StringBuilder(strLen);
7005         final int offset = -(shift % strLen);
7006         builder.append(substring(str, offset));
7007         builder.append(substring(str, 0, offset));
7008         return builder.toString();
7009     }
7010 
7011     /**
7012      * Splits the provided text into an array, using whitespace as the separator. Whitespace is defined by {@link Character#isWhitespace(char)}.
7013      *
7014      * <p>
7015      * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
7016      * StrTokenizer class.
7017      * </p>
7018      *
7019      * <p>
7020      * A {@code null} input String returns {@code null}.
7021      * </p>
7022      *
7023      * <pre>
7024      * StringUtils.split(null)       = null
7025      * StringUtils.split("")         = []
7026      * StringUtils.split("abc def")  = ["abc", "def"]
7027      * StringUtils.split("abc  def") = ["abc", "def"]
7028      * StringUtils.split(" abc ")    = ["abc"]
7029      * </pre>
7030      *
7031      * @param str the String to parse, may be null.
7032      * @return an array of parsed Strings, {@code null} if null String input.
7033      */
7034     public static String[] split(final String str) {
7035         return split(str, null, -1);
7036     }
7037 
7038     /**
7039      * Splits the provided text into an array, separator specified. This is an alternative to using StringTokenizer.
7040      *
7041      * <p>
7042      * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
7043      * StrTokenizer class.
7044      * </p>
7045      *
7046      * <p>
7047      * A {@code null} input String returns {@code null}.
7048      * </p>
7049      *
7050      * <pre>
7051      * StringUtils.split(null, *)         = null
7052      * StringUtils.split("", *)           = []
7053      * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7054      * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7055      * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7056      * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7057      * </pre>
7058      *
7059      * @param str           the String to parse, may be null.
7060      * @param separatorChar the character used as the delimiter.
7061      * @return an array of parsed Strings, {@code null} if null String input.
7062      * @since 2.0
7063      */
7064     public static String[] split(final String str, final char separatorChar) {
7065         return splitWorker(str, separatorChar, false);
7066     }
7067 
7068     /**
7069      * Splits the provided text into an array, separators specified. This is an alternative to using StringTokenizer.
7070      *
7071      * <p>
7072      * The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the
7073      * StrTokenizer class.
7074      * </p>
7075      *
7076      * <p>
7077      * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7078      * </p>
7079      *
7080      * <pre>
7081      * StringUtils.split(null, *)         = null
7082      * StringUtils.split("", *)           = []
7083      * StringUtils.split("abc def", null) = ["abc", "def"]
7084      * StringUtils.split("abc def", " ")  = ["abc", "def"]
7085      * StringUtils.split("abc  def", " ") = ["abc", "def"]
7086      * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7087      * </pre>
7088      *
7089      * @param str            the String to parse, may be null.
7090      * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7091      * @return an array of parsed Strings, {@code null} if null String input.
7092      */
7093     public static String[] split(final String str, final String separatorChars) {
7094         return splitWorker(str, separatorChars, -1, false);
7095     }
7096 
7097     /**
7098      * Splits the provided text into an array with a maximum length, separators specified.
7099      *
7100      * <p>
7101      * The separator is not included in the returned String array. Adjacent separators are treated as one separator.
7102      * </p>
7103      *
7104      * <p>
7105      * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7106      * </p>
7107      *
7108      * <p>
7109      * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7110      * strings (including separator characters).
7111      * </p>
7112      *
7113      * <pre>
7114      * StringUtils.split(null, *, *)            = null
7115      * StringUtils.split("", *, *)              = []
7116      * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7117      * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7118      * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7119      * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7120      * </pre>
7121      *
7122      * @param str            the String to parse, may be null.
7123      * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7124      * @param max            the maximum number of elements to include in the array. A zero or negative value implies no limit.
7125      * @return an array of parsed Strings, {@code null} if null String input.
7126      */
7127     public static String[] split(final String str, final String separatorChars, final int max) {
7128         return splitWorker(str, separatorChars, max, false);
7129     }
7130 
7131     /**
7132      * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
7133      * as complete tokens.
7134      *
7135      * <pre>
7136      * StringUtils.splitByCharacterType(null)         = null
7137      * StringUtils.splitByCharacterType("")           = []
7138      * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7139      * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7140      * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7141      * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7142      * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7143      * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7144      * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7145      * </pre>
7146      *
7147      * @param str the String to split, may be {@code null}.
7148      * @return an array of parsed Strings, {@code null} if null String input.
7149      * @since 2.4
7150      */
7151     public static String[] splitByCharacterType(final String str) {
7152         return splitByCharacterType(str, false);
7153     }
7154 
7155     /**
7156      * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
7157      * as complete tokens, with the following exception: if {@code camelCase} is {@code true}, the character of type {@code Character.UPPERCASE_LETTER}, if any,
7158      * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any,
7159      * {@code Character.UPPERCASE_LETTER} token.
7160      *
7161      * @param str       the String to split, may be {@code null}.
7162      * @param camelCase whether to use so-called "camel-case" for letter types.
7163      * @return an array of parsed Strings, {@code null} if null String input.
7164      * @since 2.4
7165      */
7166     private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7167         if (str == null) {
7168             return null;
7169         }
7170         if (str.isEmpty()) {
7171             return ArrayUtils.EMPTY_STRING_ARRAY;
7172         }
7173         final char[] c = str.toCharArray();
7174         final List<String> list = new ArrayList<>();
7175         int tokenStart = 0;
7176         int currentType = Character.getType(c[tokenStart]);
7177         for (int pos = tokenStart + 1; pos < c.length; pos++) {
7178             final int type = Character.getType(c[pos]);
7179             if (type == currentType) {
7180                 continue;
7181             }
7182             if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7183                 final int newTokenStart = pos - 1;
7184                 if (newTokenStart != tokenStart) {
7185                     list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7186                     tokenStart = newTokenStart;
7187                 }
7188             } else {
7189                 list.add(new String(c, tokenStart, pos - tokenStart));
7190                 tokenStart = pos;
7191             }
7192             currentType = type;
7193         }
7194         list.add(new String(c, tokenStart, c.length - tokenStart));
7195         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7196     }
7197 
7198     /**
7199      * Splits a String by Character type as returned by {@code java.lang.Character.getType(char)}. Groups of contiguous characters of the same type are returned
7200      * as complete tokens, with the following exception: the character of type {@code Character.UPPERCASE_LETTER}, if any, immediately preceding a token of type
7201      * {@code Character.LOWERCASE_LETTER} will belong to the following token rather than to the preceding, if any, {@code Character.UPPERCASE_LETTER} token.
7202      *
7203      * <pre>
7204      * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7205      * StringUtils.splitByCharacterTypeCamelCase("")           = []
7206      * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7207      * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7208      * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7209      * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7210      * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7211      * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7212      * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7213      * </pre>
7214      *
7215      * @param str the String to split, may be {@code null}.
7216      * @return an array of parsed Strings, {@code null} if null String input.
7217      * @since 2.4
7218      */
7219     public static String[] splitByCharacterTypeCamelCase(final String str) {
7220         return splitByCharacterType(str, true);
7221     }
7222 
7223     /**
7224      * Splits the provided text into an array, separator string specified.
7225      *
7226      * <p>
7227      * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7228      * </p>
7229      *
7230      * <p>
7231      * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7232      * </p>
7233      *
7234      * <pre>
7235      * StringUtils.splitByWholeSeparator(null, *)               = null
7236      * StringUtils.splitByWholeSeparator("", *)                 = []
7237      * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7238      * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7239      * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7240      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7241      * </pre>
7242      *
7243      * @param str       the String to parse, may be null.
7244      * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7245      * @return an array of parsed Strings, {@code null} if null String was input.
7246      */
7247     public static String[] splitByWholeSeparator(final String str, final String separator) {
7248         return splitByWholeSeparatorWorker(str, separator, -1, false);
7249     }
7250 
7251     /**
7252      * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7253      *
7254      * <p>
7255      * The separator(s) will not be included in the returned String array. Adjacent separators are treated as one separator.
7256      * </p>
7257      *
7258      * <p>
7259      * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7260      * </p>
7261      *
7262      * <pre>
7263      * StringUtils.splitByWholeSeparator(null, *, *)               = null
7264      * StringUtils.splitByWholeSeparator("", *, *)                 = []
7265      * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7266      * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7267      * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7268      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7269      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7270      * </pre>
7271      *
7272      * @param str       the String to parse, may be null.
7273      * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7274      * @param max       the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7275      * @return an array of parsed Strings, {@code null} if null String was input.
7276      */
7277     public static String[] splitByWholeSeparator(final String str, final String separator, final int max) {
7278         return splitByWholeSeparatorWorker(str, separator, max, false);
7279     }
7280 
7281     /**
7282      * Splits the provided text into an array, separator string specified.
7283      *
7284      * <p>
7285      * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7286      * split use the StrTokenizer class.
7287      * </p>
7288      *
7289      * <p>
7290      * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7291      * </p>
7292      *
7293      * <pre>
7294      * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7295      * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7296      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7297      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7298      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7299      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7300      * </pre>
7301      *
7302      * @param str       the String to parse, may be null.
7303      * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7304      * @return an array of parsed Strings, {@code null} if null String was input.
7305      * @since 2.4
7306      */
7307     public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7308         return splitByWholeSeparatorWorker(str, separator, -1, true);
7309     }
7310 
7311     /**
7312      * Splits the provided text into an array, separator string specified. Returns a maximum of {@code max} substrings.
7313      *
7314      * <p>
7315      * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7316      * split use the StrTokenizer class.
7317      * </p>
7318      *
7319      * <p>
7320      * A {@code null} input String returns {@code null}. A {@code null} separator splits on whitespace.
7321      * </p>
7322      *
7323      * <pre>
7324      * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7325      * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7326      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7327      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7328      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7329      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7330      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7331      * </pre>
7332      *
7333      * @param str       the String to parse, may be null.
7334      * @param separator String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7335      * @param max       the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7336      * @return an array of parsed Strings, {@code null} if null String was input.
7337      * @since 2.4
7338      */
7339     public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7340         return splitByWholeSeparatorWorker(str, separator, max, true);
7341     }
7342 
7343     /**
7344      * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7345      *
7346      * @param str               the String to parse, may be {@code null}.
7347      * @param separator         String containing the String to be used as a delimiter, {@code null} splits on whitespace.
7348      * @param max               the maximum number of elements to include in the returned array. A zero or negative value implies no limit.
7349      * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7350      *                          one separator.
7351      * @return an array of parsed Strings, {@code null} if null String input.
7352      * @since 2.4
7353      */
7354     private static String[] splitByWholeSeparatorWorker(final String str, final String separator, final int max, final boolean preserveAllTokens) {
7355         if (str == null) {
7356             return null;
7357         }
7358         final int len = str.length();
7359         if (len == 0) {
7360             return ArrayUtils.EMPTY_STRING_ARRAY;
7361         }
7362         if (separator == null || EMPTY.equals(separator)) {
7363             // Split on whitespace.
7364             return splitWorker(str, null, max, preserveAllTokens);
7365         }
7366         final int separatorLength = separator.length();
7367         final ArrayList<String> substrings = new ArrayList<>();
7368         int numberOfSubstrings = 0;
7369         int beg = 0;
7370         int end = 0;
7371         while (end < len) {
7372             end = str.indexOf(separator, beg);
7373             if (end > -1) {
7374                 if (end > beg) {
7375                     numberOfSubstrings += 1;
7376                     if (numberOfSubstrings == max) {
7377                         end = len;
7378                         substrings.add(str.substring(beg));
7379                     } else {
7380                         // The following is OK, because String.substring( beg, end ) excludes
7381                         // the character at the position 'end'.
7382                         substrings.add(str.substring(beg, end));
7383                         // Set the starting point for the next search.
7384                         // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7385                         // which is the right calculation:
7386                         beg = end + separatorLength;
7387                     }
7388                 } else {
7389                     // We found a consecutive occurrence of the separator, so skip it.
7390                     if (preserveAllTokens) {
7391                         numberOfSubstrings += 1;
7392                         if (numberOfSubstrings == max) {
7393                             end = len;
7394                             substrings.add(str.substring(beg));
7395                         } else {
7396                             substrings.add(EMPTY);
7397                         }
7398                     }
7399                     beg = end + separatorLength;
7400                 }
7401             } else {
7402                 // String.substring( beg ) goes from 'beg' to the end of the String.
7403                 substrings.add(str.substring(beg));
7404                 end = len;
7405             }
7406         }
7407         return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7408     }
7409 
7410     /**
7411      * Splits the provided text into an array, using whitespace as the separator, preserving all tokens, including empty tokens created by adjacent separators.
7412      * This is an alternative to using StringTokenizer. Whitespace is defined by {@link Character#isWhitespace(char)}.
7413      *
7414      * <p>
7415      * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7416      * split use the StrTokenizer class.
7417      * </p>
7418      *
7419      * <p>
7420      * A {@code null} input String returns {@code null}.
7421      * </p>
7422      *
7423      * <pre>
7424      * StringUtils.splitPreserveAllTokens(null)       = null
7425      * StringUtils.splitPreserveAllTokens("")         = []
7426      * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7427      * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7428      * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7429      * </pre>
7430      *
7431      * @param str the String to parse, may be {@code null}.
7432      * @return an array of parsed Strings, {@code null} if null String input.
7433      * @since 2.1
7434      */
7435     public static String[] splitPreserveAllTokens(final String str) {
7436         return splitWorker(str, null, -1, true);
7437     }
7438 
7439     /**
7440      * Splits the provided text into an array, separator specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7441      * alternative to using StringTokenizer.
7442      *
7443      * <p>
7444      * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7445      * split use the StrTokenizer class.
7446      * </p>
7447      *
7448      * <p>
7449      * A {@code null} input String returns {@code null}.
7450      * </p>
7451      *
7452      * <pre>
7453      * StringUtils.splitPreserveAllTokens(null, *)         = null
7454      * StringUtils.splitPreserveAllTokens("", *)           = []
7455      * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7456      * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7457      * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7458      * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7459      * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7460      * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7461      * StringUtils.splitPreserveAllTokens("a b c  ", ' ')  = ["a", "b", "c", "", ""]
7462      * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", "a", "b", "c"]
7463      * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", "a", "b", "c"]
7464      * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", "a", "b", "c", ""]
7465      * </pre>
7466      *
7467      * @param str           the String to parse, may be {@code null}.
7468      * @param separatorChar the character used as the delimiter, {@code null} splits on whitespace.
7469      * @return an array of parsed Strings, {@code null} if null String input.
7470      * @since 2.1
7471      */
7472     public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7473         return splitWorker(str, separatorChar, true);
7474     }
7475 
7476     /**
7477      * Splits the provided text into an array, separators specified, preserving all tokens, including empty tokens created by adjacent separators. This is an
7478      * alternative to using StringTokenizer.
7479      *
7480      * <p>
7481      * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. For more control over the
7482      * split use the StrTokenizer class.
7483      * </p>
7484      *
7485      * <p>
7486      * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7487      * </p>
7488      *
7489      * <pre>
7490      * StringUtils.splitPreserveAllTokens(null, *)           = null
7491      * StringUtils.splitPreserveAllTokens("", *)             = []
7492      * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7493      * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7494      * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", "def"]
7495      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7496      * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7497      * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7498      * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", "cd", "ef"]
7499      * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", "cd", "ef"]
7500      * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", "cd", "ef"]
7501      * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", "cd", "ef", ""]
7502      * </pre>
7503      *
7504      * @param str            the String to parse, may be {@code null}.
7505      * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7506      * @return an array of parsed Strings, {@code null} if null String input.
7507      * @since 2.1
7508      */
7509     public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7510         return splitWorker(str, separatorChars, -1, true);
7511     }
7512 
7513     /**
7514      * Splits the provided text into an array with a maximum length, separators specified, preserving all tokens, including empty tokens created by adjacent
7515      * separators.
7516      *
7517      * <p>
7518      * The separator is not included in the returned String array. Adjacent separators are treated as separators for empty tokens. Adjacent separators are
7519      * treated as one separator.
7520      * </p>
7521      *
7522      * <p>
7523      * A {@code null} input String returns {@code null}. A {@code null} separatorChars splits on whitespace.
7524      * </p>
7525      *
7526      * <p>
7527      * If more than {@code max} delimited substrings are found, the last returned string includes all characters after the first {@code max - 1} returned
7528      * strings (including separator characters).
7529      * </p>
7530      *
7531      * <pre>
7532      * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7533      * StringUtils.splitPreserveAllTokens("", *, *)              = []
7534      * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7535      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7536      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7537      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7538      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7539      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7540      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7541      * </pre>
7542      *
7543      * @param str            the String to parse, may be {@code null}.
7544      * @param separatorChars the characters used as the delimiters, {@code null} splits on whitespace.
7545      * @param max            the maximum number of elements to include in the array. A zero or negative value implies no limit.
7546      * @return an array of parsed Strings, {@code null} if null String input.
7547      * @since 2.1
7548      */
7549     public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7550         return splitWorker(str, separatorChars, max, true);
7551     }
7552 
7553     /**
7554      * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that do not return a maximum array length.
7555      *
7556      * @param str               the String to parse, may be {@code null}.
7557      * @param separatorChar     the separate character.
7558      * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7559      *                          one separator.
7560      * @return an array of parsed Strings, {@code null} if null String input.
7561      */
7562     private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7563         // Performance tuned for 2.0 (JDK1.4)
7564         if (str == null) {
7565             return null;
7566         }
7567         final int len = str.length();
7568         if (len == 0) {
7569             return ArrayUtils.EMPTY_STRING_ARRAY;
7570         }
7571         final List<String> list = new ArrayList<>();
7572         int i = 0;
7573         int start = 0;
7574         boolean match = false;
7575         boolean lastMatch = false;
7576         while (i < len) {
7577             if (str.charAt(i) == separatorChar) {
7578                 if (match || preserveAllTokens) {
7579                     list.add(str.substring(start, i));
7580                     match = false;
7581                     lastMatch = true;
7582                 }
7583                 start = ++i;
7584                 continue;
7585             }
7586             lastMatch = false;
7587             match = true;
7588             i++;
7589         }
7590         if (match || preserveAllTokens && lastMatch) {
7591             list.add(str.substring(start, i));
7592         }
7593         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7594     }
7595 
7596     /**
7597      * Performs the logic for the {@code split} and {@code splitPreserveAllTokens} methods that return a maximum array length.
7598      *
7599      * @param str               the String to parse, may be {@code null}.
7600      * @param separatorChars    the separate character.
7601      * @param max               the maximum number of elements to include in the array. A zero or negative value implies no limit.
7602      * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty token separators; if {@code false}, adjacent separators are treated as
7603      *                          one separator.
7604      * @return an array of parsed Strings, {@code null} if null String input.
7605      */
7606     private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7607         // Performance tuned for 2.0 (JDK1.4)
7608         // Direct code is quicker than StringTokenizer.
7609         // Also, StringTokenizer uses isSpace() not isWhitespace()
7610         if (str == null) {
7611             return null;
7612         }
7613         final int len = str.length();
7614         if (len == 0) {
7615             return ArrayUtils.EMPTY_STRING_ARRAY;
7616         }
7617         final List<String> list = new ArrayList<>();
7618         int sizePlus1 = 1;
7619         int i = 0;
7620         int start = 0;
7621         boolean match = false;
7622         boolean lastMatch = false;
7623         if (separatorChars == null) {
7624             // Null separator means use whitespace
7625             while (i < len) {
7626                 if (Character.isWhitespace(str.charAt(i))) {
7627                     if (match || preserveAllTokens) {
7628                         lastMatch = true;
7629                         if (sizePlus1++ == max) {
7630                             i = len;
7631                             lastMatch = false;
7632                         }
7633                         list.add(str.substring(start, i));
7634                         match = false;
7635                     }
7636                     start = ++i;
7637                     continue;
7638                 }
7639                 lastMatch = false;
7640                 match = true;
7641                 i++;
7642             }
7643         } else if (separatorChars.length() == 1) {
7644             // Optimize 1 character case
7645             final char sep = separatorChars.charAt(0);
7646             while (i < len) {
7647                 if (str.charAt(i) == sep) {
7648                     if (match || preserveAllTokens) {
7649                         lastMatch = true;
7650                         if (sizePlus1++ == max) {
7651                             i = len;
7652                             lastMatch = false;
7653                         }
7654                         list.add(str.substring(start, i));
7655                         match = false;
7656                     }
7657                     start = ++i;
7658                     continue;
7659                 }
7660                 lastMatch = false;
7661                 match = true;
7662                 i++;
7663             }
7664         } else {
7665             // standard case
7666             while (i < len) {
7667                 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7668                     if (match || preserveAllTokens) {
7669                         lastMatch = true;
7670                         if (sizePlus1++ == max) {
7671                             i = len;
7672                             lastMatch = false;
7673                         }
7674                         list.add(str.substring(start, i));
7675                         match = false;
7676                     }
7677                     start = ++i;
7678                     continue;
7679                 }
7680                 lastMatch = false;
7681                 match = true;
7682                 i++;
7683             }
7684         }
7685         if (match || preserveAllTokens && lastMatch) {
7686             list.add(str.substring(start, i));
7687         }
7688         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7689     }
7690 
7691     /**
7692      * Tests if a CharSequence starts with a specified prefix.
7693      *
7694      * <p>
7695      * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case-sensitive.
7696      * </p>
7697      *
7698      * <pre>
7699      * StringUtils.startsWith(null, null)      = true
7700      * StringUtils.startsWith(null, "abc")     = false
7701      * StringUtils.startsWith("abcdef", null)  = false
7702      * StringUtils.startsWith("abcdef", "abc") = true
7703      * StringUtils.startsWith("ABCDEF", "abc") = false
7704      * </pre>
7705      *
7706      * @param str    the CharSequence to check, may be null.
7707      * @param prefix the prefix to find, may be null.
7708      * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or both {@code null}.
7709      * @see String#startsWith(String)
7710      * @since 2.4
7711      * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7712      * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CS.startsWith(CharSequence, CharSequence)}
7713      */
7714     @Deprecated
7715     public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7716         return Strings.CS.startsWith(str, prefix);
7717     }
7718 
7719     /**
7720      * Tests if a CharSequence starts with any of the provided case-sensitive prefixes.
7721      *
7722      * <pre>
7723      * StringUtils.startsWithAny(null, null)      = false
7724      * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
7725      * StringUtils.startsWithAny("abcxyz", null)     = false
7726      * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
7727      * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
7728      * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
7729      * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
7730      * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
7731      * </pre>
7732      *
7733      * @param sequence      the CharSequence to check, may be null.
7734      * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}.
7735      * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or the input {@code sequence} begins with
7736      *         any of the provided case-sensitive {@code searchStrings}.
7737      * @see StringUtils#startsWith(CharSequence, CharSequence)
7738      * @since 2.5
7739      * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
7740      * @deprecated Use {@link Strings#startsWithAny(CharSequence, CharSequence...) Strings.CS.startsWithAny(CharSequence, CharSequence...)}
7741      */
7742     @Deprecated
7743     public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
7744         return Strings.CS.startsWithAny(sequence, searchStrings);
7745     }
7746 
7747     /**
7748      * Case-insensitive check if a CharSequence starts with a specified prefix.
7749      *
7750      * <p>
7751      * {@code null}s are handled without exceptions. Two {@code null} references are considered to be equal. The comparison is case insensitive.
7752      * </p>
7753      *
7754      * <pre>
7755      * StringUtils.startsWithIgnoreCase(null, null)      = true
7756      * StringUtils.startsWithIgnoreCase(null, "abc")     = false
7757      * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
7758      * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
7759      * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
7760      * </pre>
7761      *
7762      * @param str    the CharSequence to check, may be null.
7763      * @param prefix the prefix to find, may be null.
7764      * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or both {@code null}.
7765      * @see String#startsWith(String)
7766      * @since 2.4
7767      * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
7768      * @deprecated Use {@link Strings#startsWith(CharSequence, CharSequence) Strings.CI.startsWith(CharSequence, CharSequence)}
7769      */
7770     @Deprecated
7771     public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
7772         return Strings.CI.startsWith(str, prefix);
7773     }
7774 
7775     /**
7776      * Strips whitespace from the start and end of a String.
7777      *
7778      * <p>
7779      * This is similar to {@link #trim(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
7780      * </p>
7781      *
7782      * <p>
7783      * A {@code null} input String returns {@code null}.
7784      * </p>
7785      *
7786      * <pre>
7787      * StringUtils.strip(null)     = null
7788      * StringUtils.strip("")       = ""
7789      * StringUtils.strip("   ")    = ""
7790      * StringUtils.strip("abc")    = "abc"
7791      * StringUtils.strip("  abc")  = "abc"
7792      * StringUtils.strip("abc  ")  = "abc"
7793      * StringUtils.strip(" abc ")  = "abc"
7794      * StringUtils.strip(" ab c ") = "ab c"
7795      * </pre>
7796      *
7797      * @param str the String to remove whitespace from, may be null.
7798      * @return the stripped String, {@code null} if null String input.
7799      */
7800     public static String strip(final String str) {
7801         return strip(str, null);
7802     }
7803 
7804     /**
7805      * Strips any of a set of characters from the start and end of a String. This is similar to {@link String#trim()} but allows the characters to be stripped
7806      * to be controlled.
7807      *
7808      * <p>
7809      * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7810      * </p>
7811      *
7812      * <p>
7813      * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}. Alternatively use
7814      * {@link #strip(String)}.
7815      * </p>
7816      *
7817      * <pre>
7818      * StringUtils.strip(null, *)          = null
7819      * StringUtils.strip("", *)            = ""
7820      * StringUtils.strip("abc", null)      = "abc"
7821      * StringUtils.strip("  abc", null)    = "abc"
7822      * StringUtils.strip("abc  ", null)    = "abc"
7823      * StringUtils.strip(" abc ", null)    = "abc"
7824      * StringUtils.strip("  abcyx", "xyz") = "  abc"
7825      * </pre>
7826      *
7827      * @param str        the String to remove characters from, may be null.
7828      * @param stripChars the characters to remove, null treated as whitespace.
7829      * @return the stripped String, {@code null} if null String input.
7830      */
7831     public static String strip(String str, final String stripChars) {
7832         str = stripStart(str, stripChars);
7833         return stripEnd(str, stripChars);
7834     }
7835 
7836     /**
7837      * Removes diacritics (~= accents) from a string. The case will not be altered.
7838      * <p>
7839      * For instance, '&agrave;' will be replaced by 'a'.
7840      * </p>
7841      * <p>
7842      * Decomposes ligatures and digraphs per the KD column in the <a href = "https://www.unicode.org/charts/normalization/">Unicode Normalization Chart.</a>
7843      * </p>
7844      *
7845      * <pre>
7846      * StringUtils.stripAccents(null)         = null
7847      * StringUtils.stripAccents("")           = ""
7848      * StringUtils.stripAccents("control")    = "control"
7849      * StringUtils.stripAccents("&eacute;clair")     = "eclair"
7850      * StringUtils.stripAccents("\u1d43\u1d47\u1d9c\u00b9\u00b2\u00b3")     = "abc123"
7851      * StringUtils.stripAccents("\u00BC \u00BD \u00BE")      = "1⁄4 1⁄2 3⁄4"
7852      * </pre>
7853      * <p>
7854      * See also <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode Standard Annex #15 Unicode Normalization Forms</a>.
7855      * </p>
7856      *
7857      * @param input String to be stripped.
7858      * @return input text with diacritics removed.
7859      * @since 3.0
7860      */
7861     // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix:
7862     // https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
7863     public static String stripAccents(final String input) {
7864         if (isEmpty(input)) {
7865             return input;
7866         }
7867         final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFKD));
7868         convertRemainingAccentCharacters(decomposed);
7869         return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
7870     }
7871 
7872     /**
7873      * Strips whitespace from the start and end of every String in an array. Whitespace is defined by {@link Character#isWhitespace(char)}.
7874      *
7875      * <p>
7876      * A new array is returned each time, except for length zero. A {@code null} array will return {@code null}. An empty array will return itself. A
7877      * {@code null} array entry will be ignored.
7878      * </p>
7879      *
7880      * <pre>
7881      * StringUtils.stripAll(null)             = null
7882      * StringUtils.stripAll([])               = []
7883      * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
7884      * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
7885      * </pre>
7886      *
7887      * @param strs the array to remove whitespace from, may be null.
7888      * @return the stripped Strings, {@code null} if null array input.
7889      */
7890     public static String[] stripAll(final String... strs) {
7891         return stripAll(strs, null);
7892     }
7893 
7894     /**
7895      * Strips any of a set of characters from the start and end of every String in an array.
7896      * <p>
7897      * Whitespace is defined by {@link Character#isWhitespace(char)}.
7898      * </p>
7899      *
7900      * <p>
7901      * A new array is returned each time, except for length zero. A {@code null} array will return {@code null}. An empty array will return itself. A
7902      * {@code null} array entry will be ignored. A {@code null} stripChars will strip whitespace as defined by {@link Character#isWhitespace(char)}.
7903      * </p>
7904      *
7905      * <pre>
7906      * StringUtils.stripAll(null, *)                = null
7907      * StringUtils.stripAll([], *)                  = []
7908      * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
7909      * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
7910      * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
7911      * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
7912      * </pre>
7913      *
7914      * @param strs       the array to remove characters from, may be null.
7915      * @param stripChars the characters to remove, null treated as whitespace.
7916      * @return the stripped Strings, {@code null} if null array input.
7917      */
7918     public static String[] stripAll(final String[] strs, final String stripChars) {
7919         final int strsLen = ArrayUtils.getLength(strs);
7920         if (strsLen == 0) {
7921             return strs;
7922         }
7923         return ArrayUtils.setAll(new String[strsLen], i -> strip(strs[i], stripChars));
7924     }
7925 
7926     /**
7927      * Strips any of a set of characters from the end of a String.
7928      *
7929      * <p>
7930      * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7931      * </p>
7932      *
7933      * <p>
7934      * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
7935      * </p>
7936      *
7937      * <pre>
7938      * StringUtils.stripEnd(null, *)          = null
7939      * StringUtils.stripEnd("", *)            = ""
7940      * StringUtils.stripEnd("abc", "")        = "abc"
7941      * StringUtils.stripEnd("abc", null)      = "abc"
7942      * StringUtils.stripEnd("  abc", null)    = "  abc"
7943      * StringUtils.stripEnd("abc  ", null)    = "abc"
7944      * StringUtils.stripEnd(" abc ", null)    = " abc"
7945      * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
7946      * StringUtils.stripEnd("120.00", ".0")   = "12"
7947      * </pre>
7948      *
7949      * @param str        the String to remove characters from, may be null.
7950      * @param stripChars the set of characters to remove, null treated as whitespace.
7951      * @return the stripped String, {@code null} if null String input.
7952      */
7953     public static String stripEnd(final String str, final String stripChars) {
7954         int end = length(str);
7955         if (end == 0) {
7956             return str;
7957         }
7958         if (stripChars == null) {
7959             while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
7960                 end--;
7961             }
7962         } else if (stripChars.isEmpty()) {
7963             return str;
7964         } else {
7965             while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
7966                 end--;
7967             }
7968         }
7969         return str.substring(0, end);
7970     }
7971 
7972     /**
7973      * Strips any of a set of characters from the start of a String.
7974      *
7975      * <p>
7976      * A {@code null} input String returns {@code null}. An empty string ("") input returns the empty string.
7977      * </p>
7978      *
7979      * <p>
7980      * If the stripChars String is {@code null}, whitespace is stripped as defined by {@link Character#isWhitespace(char)}.
7981      * </p>
7982      *
7983      * <pre>
7984      * StringUtils.stripStart(null, *)          = null
7985      * StringUtils.stripStart("", *)            = ""
7986      * StringUtils.stripStart("abc", "")        = "abc"
7987      * StringUtils.stripStart("abc", null)      = "abc"
7988      * StringUtils.stripStart("  abc", null)    = "abc"
7989      * StringUtils.stripStart("abc  ", null)    = "abc  "
7990      * StringUtils.stripStart(" abc ", null)    = "abc "
7991      * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
7992      * </pre>
7993      *
7994      * @param str        the String to remove characters from, may be null.
7995      * @param stripChars the characters to remove, null treated as whitespace.
7996      * @return the stripped String, {@code null} if null String input.
7997      */
7998     public static String stripStart(final String str, final String stripChars) {
7999         final int strLen = length(str);
8000         if (strLen == 0) {
8001             return str;
8002         }
8003         int start = 0;
8004         if (stripChars == null) {
8005             while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8006                 start++;
8007             }
8008         } else if (stripChars.isEmpty()) {
8009             return str;
8010         } else {
8011             while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
8012                 start++;
8013             }
8014         }
8015         return str.substring(start);
8016     }
8017 
8018     /**
8019      * Strips whitespace from the start and end of a String returning an empty String if {@code null} input.
8020      *
8021      * <p>
8022      * This is similar to {@link #trimToEmpty(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8023      * </p>
8024      *
8025      * <pre>
8026      * StringUtils.stripToEmpty(null)     = ""
8027      * StringUtils.stripToEmpty("")       = ""
8028      * StringUtils.stripToEmpty("   ")    = ""
8029      * StringUtils.stripToEmpty("abc")    = "abc"
8030      * StringUtils.stripToEmpty("  abc")  = "abc"
8031      * StringUtils.stripToEmpty("abc  ")  = "abc"
8032      * StringUtils.stripToEmpty(" abc ")  = "abc"
8033      * StringUtils.stripToEmpty(" ab c ") = "ab c"
8034      * </pre>
8035      *
8036      * @param str the String to be stripped, may be null.
8037      * @return the trimmed String, or an empty String if {@code null} input.
8038      * @since 2.0
8039      */
8040     public static String stripToEmpty(final String str) {
8041         return str == null ? EMPTY : strip(str, null);
8042     }
8043 
8044     /**
8045      * Strips whitespace from the start and end of a String returning {@code null} if the String is empty ("") after the strip.
8046      *
8047      * <p>
8048      * This is similar to {@link #trimToNull(String)} but removes whitespace. Whitespace is defined by {@link Character#isWhitespace(char)}.
8049      * </p>
8050      *
8051      * <pre>
8052      * StringUtils.stripToNull(null)     = null
8053      * StringUtils.stripToNull("")       = null
8054      * StringUtils.stripToNull("   ")    = null
8055      * StringUtils.stripToNull("abc")    = "abc"
8056      * StringUtils.stripToNull("  abc")  = "abc"
8057      * StringUtils.stripToNull("abc  ")  = "abc"
8058      * StringUtils.stripToNull(" abc ")  = "abc"
8059      * StringUtils.stripToNull(" ab c ") = "ab c"
8060      * </pre>
8061      *
8062      * @param str the String to be stripped, may be null.
8063      * @return the stripped String, {@code null} if whitespace, empty or null String input.
8064      * @since 2.0
8065      */
8066     public static String stripToNull(String str) {
8067         if (str == null) {
8068             return null;
8069         }
8070         str = strip(str, null);
8071         return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8072     }
8073 
8074     /**
8075      * Gets a substring from the specified String avoiding exceptions.
8076      *
8077      * <p>
8078      * A negative start position can be used to start {@code n} characters from the end of the String.
8079      * </p>
8080      *
8081      * <p>
8082      * A {@code null} String will return {@code null}. An empty ("") String will return "".
8083      * </p>
8084      *
8085      * <pre>
8086      * StringUtils.substring(null, *)   = null
8087      * StringUtils.substring("", *)     = ""
8088      * StringUtils.substring("abc", 0)  = "abc"
8089      * StringUtils.substring("abc", 2)  = "c"
8090      * StringUtils.substring("abc", 4)  = ""
8091      * StringUtils.substring("abc", -2) = "bc"
8092      * StringUtils.substring("abc", -4) = "abc"
8093      * </pre>
8094      *
8095      * @param str   the String to get the substring from, may be null.
8096      * @param start the position to start from, negative means count back from the end of the String by this many characters.
8097      * @return substring from start position, {@code null} if null String input.
8098      */
8099     public static String substring(final String str, int start) {
8100         if (str == null) {
8101             return null;
8102         }
8103         // handle negatives, which means last n characters
8104         if (start < 0) {
8105             start = str.length() + start; // remember start is negative
8106         }
8107         if (start < 0) {
8108             start = 0;
8109         }
8110         if (start > str.length()) {
8111             return EMPTY;
8112         }
8113         return str.substring(start);
8114     }
8115 
8116     /**
8117      * Gets a substring from the specified String avoiding exceptions.
8118      *
8119      * <p>
8120      * A negative start position can be used to start/end {@code n} characters from the end of the String.
8121      * </p>
8122      *
8123      * <p>
8124      * The returned substring starts with the character in the {@code start} position and ends before the {@code end} position. All position counting is
8125      * zero-based -- i.e., to start at the beginning of the string use {@code start = 0}. Negative start and end positions can be used to specify offsets
8126      * relative to the end of the String.
8127      * </p>
8128      *
8129      * <p>
8130      * If {@code start} is not strictly to the left of {@code end}, "" is returned.
8131      * </p>
8132      *
8133      * <pre>
8134      * StringUtils.substring(null, *, *)    = null
8135      * StringUtils.substring("", * ,  *)    = "";
8136      * StringUtils.substring("abc", 0, 2)   = "ab"
8137      * StringUtils.substring("abc", 2, 0)   = ""
8138      * StringUtils.substring("abc", 2, 4)   = "c"
8139      * StringUtils.substring("abc", 4, 6)   = ""
8140      * StringUtils.substring("abc", 2, 2)   = ""
8141      * StringUtils.substring("abc", -2, -1) = "b"
8142      * StringUtils.substring("abc", -4, 2)  = "ab"
8143      * </pre>
8144      *
8145      * @param str   the String to get the substring from, may be null.
8146      * @param start the position to start from, negative means count back from the end of the String by this many characters.
8147      * @param end   the position to end at (exclusive), negative means count back from the end of the String by this many characters.
8148      * @return substring from start position to end position, {@code null} if null String input.
8149      */
8150     public static String substring(final String str, int start, int end) {
8151         if (str == null) {
8152             return null;
8153         }
8154         // handle negatives
8155         if (end < 0) {
8156             end = str.length() + end; // remember end is negative
8157         }
8158         if (start < 0) {
8159             start = str.length() + start; // remember start is negative
8160         }
8161         // check length next
8162         if (end > str.length()) {
8163             end = str.length();
8164         }
8165         // if start is greater than end, return ""
8166         if (start > end) {
8167             return EMPTY;
8168         }
8169         if (start < 0) {
8170             start = 0;
8171         }
8172         if (end < 0) {
8173             end = 0;
8174         }
8175         return str.substring(start, end);
8176     }
8177 
8178     /**
8179      * Gets the substring after the first occurrence of a separator. The separator is not returned.
8180      *
8181      * <p>
8182      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8183      *
8184      * <p>
8185      * If nothing is found, the empty string is returned.
8186      * </p>
8187      *
8188      * <pre>
8189      * StringUtils.substringAfter(null, *)      = null
8190      * StringUtils.substringAfter("", *)        = ""
8191      * StringUtils.substringAfter("abc", 'a')   = "bc"
8192      * StringUtils.substringAfter("abcba", 'b') = "cba"
8193      * StringUtils.substringAfter("abc", 'c')   = ""
8194      * StringUtils.substringAfter("abc", 'd')   = ""
8195      * StringUtils.substringAfter(" abc", 32)   = "abc"
8196      * </pre>
8197      *
8198      * @param str       the String to get a substring from, may be null.
8199      * @param find the character (Unicode code point) to find.
8200      * @return the substring after the first occurrence of the specified character, {@code null} if null String input.
8201      * @since 3.11
8202      */
8203     public static String substringAfter(final String str, final int find) {
8204         if (isEmpty(str)) {
8205             return str;
8206         }
8207         final int pos = str.indexOf(find);
8208         if (pos == INDEX_NOT_FOUND) {
8209             return EMPTY;
8210         }
8211         return str.substring(pos + 1);
8212     }
8213 
8214     /**
8215      * Gets the substring after the first occurrence of a separator. The separator is not returned.
8216      *
8217      * <p>
8218      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. A {@code null} separator will return the
8219      * empty string if the input string is not {@code null}.
8220      * </p>
8221      *
8222      * <p>
8223      * If nothing is found, the empty string is returned.
8224      * </p>
8225      *
8226      * <pre>
8227      * StringUtils.substringAfter(null, *)      = null
8228      * StringUtils.substringAfter("", *)        = ""
8229      * StringUtils.substringAfter(*, null)      = ""
8230      * StringUtils.substringAfter("abc", "a")   = "bc"
8231      * StringUtils.substringAfter("abcba", "b") = "cba"
8232      * StringUtils.substringAfter("abc", "c")   = ""
8233      * StringUtils.substringAfter("abc", "d")   = ""
8234      * StringUtils.substringAfter("abc", "")    = "abc"
8235      * </pre>
8236      *
8237      * @param str       the String to get a substring from, may be null.
8238      * @param find the String to find, may be null.
8239      * @return the substring after the first occurrence of the specified string, {@code null} if null String input.
8240      * @since 2.0
8241      */
8242     public static String substringAfter(final String str, final String find) {
8243         if (isEmpty(str)) {
8244             return str;
8245         }
8246         if (find == null) {
8247             return EMPTY;
8248         }
8249         final int pos = str.indexOf(find);
8250         if (pos == INDEX_NOT_FOUND) {
8251             return EMPTY;
8252         }
8253         return str.substring(pos + find.length());
8254     }
8255 
8256     /**
8257      * Gets the substring after the last occurrence of a separator. The separator is not returned.
8258      *
8259      * <p>
8260      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8261      *
8262      * <p>
8263      * If nothing is found, the empty string is returned.
8264      * </p>
8265      *
8266      * <pre>
8267      * StringUtils.substringAfterLast(null, *)      = null
8268      * StringUtils.substringAfterLast("", *)        = ""
8269      * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8270      * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8271      * StringUtils.substringAfterLast("abcba", 'b') = "a"
8272      * StringUtils.substringAfterLast("abc", 'c')   = ""
8273      * StringUtils.substringAfterLast("a", 'a')     = ""
8274      * StringUtils.substringAfterLast("a", 'z')     = ""
8275      * </pre>
8276      *
8277      * @param str       the String to get a substring from, may be null.
8278      * @param find the character (Unicode code point) to find.
8279      * @return the substring after the last occurrence of the specified character, {@code null} if null String input.
8280      * @since 3.11
8281      */
8282     public static String substringAfterLast(final String str, final int find) {
8283         if (isEmpty(str)) {
8284             return str;
8285         }
8286         final int pos = str.lastIndexOf(find);
8287         if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8288             return EMPTY;
8289         }
8290         return str.substring(pos + 1);
8291     }
8292 
8293     /**
8294      * Gets the substring after the last occurrence of a separator. The separator is not returned.
8295      *
8296      * <p>
8297      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. An empty or {@code null} separator will
8298      * return the empty string if the input string is not {@code null}.
8299      * </p>
8300      *
8301      * <p>
8302      * If nothing is found, the empty string is returned.
8303      * </p>
8304      *
8305      * <pre>
8306      * StringUtils.substringAfterLast(null, *)      = null
8307      * StringUtils.substringAfterLast("", *)        = ""
8308      * StringUtils.substringAfterLast(*, "")        = ""
8309      * StringUtils.substringAfterLast(*, null)      = ""
8310      * StringUtils.substringAfterLast("abc", "a")   = "bc"
8311      * StringUtils.substringAfterLast("abcba", "b") = "a"
8312      * StringUtils.substringAfterLast("abc", "c")   = ""
8313      * StringUtils.substringAfterLast("a", "a")     = ""
8314      * StringUtils.substringAfterLast("a", "z")     = ""
8315      * </pre>
8316      *
8317      * @param str       the String to get a substring from, may be null.
8318      * @param find the String to find, may be null.
8319      * @return the substring after the last occurrence of the specified string, {@code null} if null String input.
8320      * @since 2.0
8321      */
8322     public static String substringAfterLast(final String str, final String find) {
8323         if (isEmpty(str)) {
8324             return str;
8325         }
8326         if (isEmpty(find)) {
8327             return EMPTY;
8328         }
8329         final int pos = str.lastIndexOf(find);
8330         if (pos == INDEX_NOT_FOUND || pos == str.length() - find.length()) {
8331             return EMPTY;
8332         }
8333         return str.substring(pos + find.length());
8334     }
8335 
8336     /**
8337      * Gets the substring before the first occurrence of a separator. The separator is not returned.
8338      *
8339      * <p>
8340      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8341      * </p>
8342      *
8343      * <p>
8344      * If nothing is found, the string input is returned.
8345      * </p>
8346      *
8347      * <pre>
8348      * StringUtils.substringBefore(null, *)      = null
8349      * StringUtils.substringBefore("", *)        = ""
8350      * StringUtils.substringBefore("abc", 'a')   = ""
8351      * StringUtils.substringBefore("abcba", 'b') = "a"
8352      * StringUtils.substringBefore("abc", 'c')   = "ab"
8353      * StringUtils.substringBefore("abc", 'd')   = "abc"
8354      * </pre>
8355      *
8356      * @param str       the String to get a substring from, may be null.
8357      * @param find the character (Unicode code point) to find.
8358      * @return the substring before the first occurrence of the specified character, {@code null} if null String input.
8359      * @since 3.12.0
8360      */
8361     public static String substringBefore(final String str, final int find) {
8362         if (isEmpty(str)) {
8363             return str;
8364         }
8365         final int pos = str.indexOf(find);
8366         if (pos == INDEX_NOT_FOUND) {
8367             return str;
8368         }
8369         return str.substring(0, pos);
8370     }
8371 
8372     /**
8373      * Gets the substring before the first occurrence of a separator. The separator is not returned.
8374      *
8375      * <p>
8376      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. A {@code null} separator will return the
8377      * input string.
8378      * </p>
8379      *
8380      * <p>
8381      * If nothing is found, the string input is returned.
8382      * </p>
8383      *
8384      * <pre>
8385      * StringUtils.substringBefore(null, *)      = null
8386      * StringUtils.substringBefore("", *)        = ""
8387      * StringUtils.substringBefore("abc", "a")   = ""
8388      * StringUtils.substringBefore("abcba", "b") = "a"
8389      * StringUtils.substringBefore("abc", "c")   = "ab"
8390      * StringUtils.substringBefore("abc", "d")   = "abc"
8391      * StringUtils.substringBefore("abc", "")    = ""
8392      * StringUtils.substringBefore("abc", null)  = "abc"
8393      * </pre>
8394      *
8395      * @param str       the String to get a substring from, may be null.
8396      * @param find the String to find, may be null.
8397      * @return the substring before the first occurrence of the specified string, {@code null} if null String input.
8398      * @since 2.0
8399      */
8400     public static String substringBefore(final String str, final String find) {
8401         if (isEmpty(str) || find == null) {
8402             return str;
8403         }
8404         if (find.isEmpty()) {
8405             return EMPTY;
8406         }
8407         final int pos = str.indexOf(find);
8408         if (pos == INDEX_NOT_FOUND) {
8409             return str;
8410         }
8411         return str.substring(0, pos);
8412     }
8413 
8414     /**
8415      * Gets the substring before the last occurrence of a separator. The separator is not returned.
8416      *
8417      * <p>
8418      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string. An empty or {@code null} separator will
8419      * return the input string.
8420      * </p>
8421      *
8422      * <p>
8423      * If nothing is found, the string input is returned.
8424      * </p>
8425      *
8426      * <pre>
8427      * StringUtils.substringBeforeLast(null, *)      = null
8428      * StringUtils.substringBeforeLast("", *)        = ""
8429      * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8430      * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8431      * StringUtils.substringBeforeLast("a", "a")     = ""
8432      * StringUtils.substringBeforeLast("a", "z")     = "a"
8433      * StringUtils.substringBeforeLast("a", null)    = "a"
8434      * StringUtils.substringBeforeLast("a", "")      = "a"
8435      * </pre>
8436      *
8437      * @param str       the String to get a substring from, may be null.
8438      * @param find the String to find, may be null.
8439      * @return the substring before the last occurrence of the specified string, {@code null} if null String input.
8440      * @since 2.0
8441      */
8442     public static String substringBeforeLast(final String str, final String find) {
8443         if (isEmpty(str) || isEmpty(find)) {
8444             return str;
8445         }
8446         final int pos = str.lastIndexOf(find);
8447         if (pos == INDEX_NOT_FOUND) {
8448             return str;
8449         }
8450         return str.substring(0, pos);
8451     }
8452 
8453     /**
8454      * Gets the String that is nested in between two instances of the same String.
8455      *
8456      * <p>
8457      * A {@code null} input String returns {@code null}. A {@code null} tag returns {@code null}.
8458      * </p>
8459      *
8460      * <pre>
8461      * StringUtils.substringBetween(null, *)            = null
8462      * StringUtils.substringBetween("", "")             = ""
8463      * StringUtils.substringBetween("", "tag")          = null
8464      * StringUtils.substringBetween("tagabctag", null)  = null
8465      * StringUtils.substringBetween("tagabctag", "")    = ""
8466      * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8467      * </pre>
8468      *
8469      * @param str the String containing the substring, may be null.
8470      * @param tag the String before and after the substring, may be null.
8471      * @return the substring, {@code null} if no match.
8472      * @since 2.0
8473      */
8474     public static String substringBetween(final String str, final String tag) {
8475         return substringBetween(str, tag, tag);
8476     }
8477 
8478     /**
8479      * Gets the String that is nested in between two Strings. Only the first match is returned.
8480      *
8481      * <p>
8482      * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open and close returns an
8483      * empty string.
8484      * </p>
8485      *
8486      * <pre>
8487      * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8488      * StringUtils.substringBetween(null, *, *)          = null
8489      * StringUtils.substringBetween(*, null, *)          = null
8490      * StringUtils.substringBetween(*, *, null)          = null
8491      * StringUtils.substringBetween("", "", "")          = ""
8492      * StringUtils.substringBetween("", "", "]")         = null
8493      * StringUtils.substringBetween("", "[", "]")        = null
8494      * StringUtils.substringBetween("yabcz", "", "")     = ""
8495      * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8496      * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8497      * </pre>
8498      *
8499      * @param str   the String containing the substring, may be null.
8500      * @param open  the String before the substring, may be null.
8501      * @param close the String after the substring, may be null.
8502      * @return the substring, {@code null} if no match.
8503      * @since 2.0
8504      */
8505     public static String substringBetween(final String str, final String open, final String close) {
8506         if (!ObjectUtils.allNotNull(str, open, close)) {
8507             return null;
8508         }
8509         final int start = str.indexOf(open);
8510         if (start != INDEX_NOT_FOUND) {
8511             final int end = str.indexOf(close, start + open.length());
8512             if (end != INDEX_NOT_FOUND) {
8513                 return str.substring(start + open.length(), end);
8514             }
8515         }
8516         return null;
8517     }
8518 
8519     /**
8520      * Searches a String for substrings delimited by a start and end tag, returning all matching substrings in an array.
8521      *
8522      * <p>
8523      * A {@code null} input String returns {@code null}. A {@code null} open/close returns {@code null} (no match). An empty ("") open/close returns
8524      * {@code null} (no match).
8525      * </p>
8526      *
8527      * <pre>
8528      * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8529      * StringUtils.substringsBetween(null, *, *)            = null
8530      * StringUtils.substringsBetween(*, null, *)            = null
8531      * StringUtils.substringsBetween(*, *, null)            = null
8532      * StringUtils.substringsBetween("", "[", "]")          = []
8533      * </pre>
8534      *
8535      * @param str   the String containing the substrings, null returns null, empty returns empty.
8536      * @param open  the String identifying the start of the substring, empty returns null.
8537      * @param close the String identifying the end of the substring, empty returns null.
8538      * @return a String Array of substrings, or {@code null} if no match.
8539      * @since 2.3
8540      */
8541     public static String[] substringsBetween(final String str, final String open, final String close) {
8542         if (str == null || isEmpty(open) || isEmpty(close)) {
8543             return null;
8544         }
8545         final int strLen = str.length();
8546         if (strLen == 0) {
8547             return ArrayUtils.EMPTY_STRING_ARRAY;
8548         }
8549         final int closeLen = close.length();
8550         final int openLen = open.length();
8551         final List<String> list = new ArrayList<>();
8552         int pos = 0;
8553         while (pos < strLen - closeLen) {
8554             int start = str.indexOf(open, pos);
8555             if (start < 0) {
8556                 break;
8557             }
8558             start += openLen;
8559             final int end = str.indexOf(close, start);
8560             if (end < 0) {
8561                 break;
8562             }
8563             list.add(str.substring(start, end));
8564             pos = end + closeLen;
8565         }
8566         if (list.isEmpty()) {
8567             return null;
8568         }
8569         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8570     }
8571 
8572     /**
8573      * Swaps the case of a String changing upper and title case to lower case, and lower case to upper case.
8574      *
8575      * <ul>
8576      * <li>Upper case character converts to Lower case</li>
8577      * <li>Title case character converts to Lower case</li>
8578      * <li>Lower case character converts to Upper case</li>
8579      * </ul>
8580      *
8581      * <p>
8582      * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}. A {@code null} input String returns {@code null}.
8583      * </p>
8584      *
8585      * <pre>
8586      * StringUtils.swapCase(null)                 = null
8587      * StringUtils.swapCase("")                   = ""
8588      * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8589      * </pre>
8590      *
8591      * <p>
8592      * NOTE: This method changed in Lang version 2.0. It no longer performs a word based algorithm. If you only use ASCII, you will notice no change. That
8593      * functionality is available in org.apache.commons.lang3.text.WordUtils.
8594      * </p>
8595      *
8596      * @param str the String to swap case, may be null.
8597      * @return the changed String, {@code null} if null String input.
8598      */
8599     public static String swapCase(final String str) {
8600         if (isEmpty(str)) {
8601             return str;
8602         }
8603         final int strLen = str.length();
8604         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8605         int outOffset = 0;
8606         for (int i = 0; i < strLen;) {
8607             final int oldCodepoint = str.codePointAt(i);
8608             final int newCodePoint;
8609             if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8610                 newCodePoint = Character.toLowerCase(oldCodepoint);
8611             } else if (Character.isLowerCase(oldCodepoint)) {
8612                 newCodePoint = Character.toUpperCase(oldCodepoint);
8613             } else {
8614                 newCodePoint = oldCodepoint;
8615             }
8616             newCodePoints[outOffset++] = newCodePoint;
8617             i += Character.charCount(newCodePoint);
8618         }
8619         return new String(newCodePoints, 0, outOffset);
8620     }
8621 
8622     /**
8623      * Converts a {@link CharSequence} into an array of code points.
8624      *
8625      * <p>
8626      * Valid pairs of surrogate code units will be converted into a single supplementary code point. Isolated surrogate code units (i.e. a high surrogate not
8627      * followed by a low surrogate or a low surrogate not preceded by a high surrogate) will be returned as-is.
8628      * </p>
8629      *
8630      * <pre>
8631      * StringUtils.toCodePoints(null)   =  null
8632      * StringUtils.toCodePoints("")     =  []  // empty array
8633      * </pre>
8634      *
8635      * @param cs the character sequence to convert.
8636      * @return an array of code points.
8637      * @since 3.6
8638      */
8639     public static int[] toCodePoints(final CharSequence cs) {
8640         if (cs == null) {
8641             return null;
8642         }
8643         if (cs.length() == 0) {
8644             return ArrayUtils.EMPTY_INT_ARRAY;
8645         }
8646         return cs.toString().codePoints().toArray();
8647     }
8648 
8649     /**
8650      * Converts a {@code byte[]} to a String using the specified character encoding.
8651      *
8652      * @param bytes   the byte array to read from.
8653      * @param charset the encoding to use, if null then use the platform default.
8654      * @return a new String.
8655      * @throws NullPointerException if {@code bytes} is null
8656      * @since 3.2
8657      * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8658      */
8659     public static String toEncodedString(final byte[] bytes, final Charset charset) {
8660         return new String(bytes, Charsets.toCharset(charset));
8661     }
8662 
8663     /**
8664      * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
8665      *
8666      * @param source A source String or null.
8667      * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
8668      * @since 3.10
8669      */
8670     public static String toRootLowerCase(final String source) {
8671         return source == null ? null : source.toLowerCase(Locale.ROOT);
8672     }
8673 
8674     /**
8675      * Converts the given source String as an upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
8676      *
8677      * @param source A source String or null.
8678      * @return the given source String as an upper-case using the {@link Locale#ROOT} locale or null.
8679      * @since 3.10
8680      */
8681     public static String toRootUpperCase(final String source) {
8682         return source == null ? null : source.toUpperCase(Locale.ROOT);
8683     }
8684 
8685     /**
8686      * Converts a {@code byte[]} to a String using the specified character encoding.
8687      *
8688      * @param bytes       the byte array to read from.
8689      * @param charsetName the encoding to use, if null then use the platform default.
8690      * @return a new String.
8691      * @throws NullPointerException if the input is null.
8692      * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8693      * @since 3.1
8694      */
8695     @Deprecated
8696     public static String toString(final byte[] bytes, final String charsetName) {
8697         return new String(bytes, Charsets.toCharset(charsetName));
8698     }
8699 
8700     /**
8701      * Removes control characters (char &lt;= 32) from both ends of this String, handling {@code null} by returning {@code null}.
8702      *
8703      * <p>
8704      * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #strip(String)}.
8705      * </p>
8706      *
8707      * <p>
8708      * To trim your choice of characters, use the {@link #strip(String, String)} methods.
8709      * </p>
8710      *
8711      * <pre>
8712      * StringUtils.trim(null)          = null
8713      * StringUtils.trim("")            = ""
8714      * StringUtils.trim("     ")       = ""
8715      * StringUtils.trim("abc")         = "abc"
8716      * StringUtils.trim("    abc    ") = "abc"
8717      * </pre>
8718      *
8719      * @param str the String to be trimmed, may be null.
8720      * @return the trimmed string, {@code null} if null String input.
8721      */
8722     public static String trim(final String str) {
8723         return str == null ? null : str.trim();
8724     }
8725 
8726     /**
8727      * Removes control characters (char &lt;= 32) from both ends of this String returning an empty String ("") if the String is empty ("") after the trim or if
8728      * it is {@code null}.
8729      *
8730      * <p>
8731      * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToEmpty(String)}.
8732      *
8733      * <pre>
8734      * StringUtils.trimToEmpty(null)          = ""
8735      * StringUtils.trimToEmpty("")            = ""
8736      * StringUtils.trimToEmpty("     ")       = ""
8737      * StringUtils.trimToEmpty("abc")         = "abc"
8738      * StringUtils.trimToEmpty("    abc    ") = "abc"
8739      * </pre>
8740      *
8741      * @param str the String to be trimmed, may be null.
8742      * @return the trimmed String, or an empty String if {@code null} input.
8743      * @since 2.0
8744      */
8745     public static String trimToEmpty(final String str) {
8746         return str == null ? EMPTY : str.trim();
8747     }
8748 
8749     /**
8750      * Removes control characters (char &lt;= 32) from both ends of this String returning {@code null} if the String is empty ("") after the trim or if it is
8751      * {@code null}.
8752      *
8753      * <p>
8754      * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32. To strip whitespace use {@link #stripToNull(String)}.
8755      *
8756      * <pre>
8757      * StringUtils.trimToNull(null)          = null
8758      * StringUtils.trimToNull("")            = null
8759      * StringUtils.trimToNull("     ")       = null
8760      * StringUtils.trimToNull("abc")         = "abc"
8761      * StringUtils.trimToNull("    abc    ") = "abc"
8762      * </pre>
8763      *
8764      * @param str the String to be trimmed, may be null.
8765      * @return the trimmed String, {@code null} if only chars &lt;= 32, empty or null String input.
8766      * @since 2.0
8767      */
8768     public static String trimToNull(final String str) {
8769         final String ts = trim(str);
8770         return isEmpty(ts) ? null : ts;
8771     }
8772 
8773     /**
8774      * Truncates a String. This will turn "Now is the time for all good men" into "Now is the time for".
8775      *
8776      * <p>
8777      * Specifically:
8778      * </p>
8779      * <ul>
8780      * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
8781      * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
8782      * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8783      * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
8784      * </ul>
8785      *
8786      * <pre>
8787      * StringUtils.truncate(null, 0)       = null
8788      * StringUtils.truncate(null, 2)       = null
8789      * StringUtils.truncate("", 4)         = ""
8790      * StringUtils.truncate("abcdefg", 4)  = "abcd"
8791      * StringUtils.truncate("abcdefg", 6)  = "abcdef"
8792      * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
8793      * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
8794      * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
8795      * </pre>
8796      *
8797      * @param str      the String to truncate, may be null.
8798      * @param maxWidth maximum length of result String, must be positive.
8799      * @return truncated String, {@code null} if null String input.
8800      * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}.
8801      * @since 3.5
8802      */
8803     public static String truncate(final String str, final int maxWidth) {
8804         return truncate(str, 0, maxWidth);
8805     }
8806 
8807     /**
8808      * Truncates a String. This will turn "Now is the time for all good men" into "is the time for all".
8809      *
8810      * <p>
8811      * Works like {@code truncate(String, int)}, but allows you to specify a "left edge" offset.
8812      *
8813      * <p>
8814      * Specifically:
8815      * </p>
8816      * <ul>
8817      * <li>If {@code str} is less than {@code maxWidth} characters long, return it.</li>
8818      * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
8819      * <li>If {@code maxWidth} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8820      * <li>If {@code offset} is less than {@code 0}, throw an {@link IllegalArgumentException}.</li>
8821      * <li>In no case will it return a String of length greater than {@code maxWidth}.</li>
8822      * </ul>
8823      *
8824      * <pre>
8825      * StringUtils.truncate(null, 0, 0) = null
8826      * StringUtils.truncate(null, 2, 4) = null
8827      * StringUtils.truncate("", 0, 10) = ""
8828      * StringUtils.truncate("", 2, 10) = ""
8829      * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
8830      * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
8831      * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
8832      * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
8833      * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
8834      * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
8835      * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
8836      * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
8837      * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
8838      * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
8839      * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
8840      * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
8841      * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
8842      * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
8843      * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
8844      * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
8845      * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
8846      * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
8847      * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
8848      * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
8849      * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
8850      * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
8851      * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
8852      * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
8853      * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
8854      * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
8855      * </pre>
8856      *
8857      * @param str      the String to truncate, may be null.
8858      * @param offset   left edge of source String.
8859      * @param maxWidth maximum length of result String, must be positive.
8860      * @return truncated String, {@code null} if null String input.
8861      * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}.
8862      * @since 3.5
8863      */
8864     public static String truncate(final String str, final int offset, final int maxWidth) {
8865         if (offset < 0) {
8866             throw new IllegalArgumentException("offset cannot be negative");
8867         }
8868         if (maxWidth < 0) {
8869             throw new IllegalArgumentException("maxWith cannot be negative");
8870         }
8871         if (str == null) {
8872             return null;
8873         }
8874         if (offset > str.length()) {
8875             return EMPTY;
8876         }
8877         if (str.length() > maxWidth) {
8878             final int ix = Math.min(offset + maxWidth, str.length());
8879             return str.substring(offset, ix);
8880         }
8881         return str.substring(offset);
8882     }
8883 
8884     /**
8885      * Uncapitalizes a String, changing the first character to lower case as per {@link Character#toLowerCase(int)}. No other characters are changed.
8886      *
8887      * <p>
8888      * For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}. A {@code null} input String returns {@code null}.
8889      * </p>
8890      *
8891      * <pre>
8892      * StringUtils.uncapitalize(null)  = null
8893      * StringUtils.uncapitalize("")    = ""
8894      * StringUtils.uncapitalize("cat") = "cat"
8895      * StringUtils.uncapitalize("Cat") = "cat"
8896      * StringUtils.uncapitalize("CAT") = "cAT"
8897      * </pre>
8898      *
8899      * @param str the String to uncapitalize, may be null.
8900      * @return the uncapitalized String, {@code null} if null String input.
8901      * @see org.apache.commons.text.WordUtils#uncapitalize(String)
8902      * @see #capitalize(String)
8903      * @since 2.0
8904      */
8905     public static String uncapitalize(final String str) {
8906         final int strLen = length(str);
8907         if (strLen == 0) {
8908             return str;
8909         }
8910         final int firstCodePoint = str.codePointAt(0);
8911         final int newCodePoint = Character.toLowerCase(firstCodePoint);
8912         if (firstCodePoint == newCodePoint) {
8913             // already uncapitalized
8914             return str;
8915         }
8916         final int[] newCodePoints = str.codePoints().toArray();
8917         newCodePoints[0] = newCodePoint; // copy the first code point
8918         return new String(newCodePoints, 0, newCodePoints.length);
8919     }
8920 
8921     /**
8922      * Unwraps a given string from a character.
8923      *
8924      * <pre>
8925      * StringUtils.unwrap(null, null)         = null
8926      * StringUtils.unwrap(null, '\0')         = null
8927      * StringUtils.unwrap(null, '1')          = null
8928      * StringUtils.unwrap("a", 'a')           = "a"
8929      * StringUtils.unwrap("aa", 'a')           = ""
8930      * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
8931      * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
8932      * StringUtils.unwrap("A", '#')           = "A"
8933      * StringUtils.unwrap("#A", '#')          = "#A"
8934      * StringUtils.unwrap("A#", '#')          = "A#"
8935      * </pre>
8936      *
8937      * @param str      the String to be unwrapped, can be null.
8938      * @param wrapChar the character used to unwrap.
8939      * @return unwrapped String or the original string if it is not quoted properly with the wrapChar.
8940      * @since 3.6
8941      */
8942     public static String unwrap(final String str, final char wrapChar) {
8943         if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
8944             return str;
8945         }
8946         if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
8947             final int startIndex = 0;
8948             final int endIndex = str.length() - 1;
8949             return str.substring(startIndex + 1, endIndex);
8950         }
8951         return str;
8952     }
8953 
8954     /**
8955      * Unwraps a given string from another string.
8956      *
8957      * <pre>
8958      * StringUtils.unwrap(null, null)         = null
8959      * StringUtils.unwrap(null, "")           = null
8960      * StringUtils.unwrap(null, "1")          = null
8961      * StringUtils.unwrap("a", "a")           = "a"
8962      * StringUtils.unwrap("aa", "a")          = ""
8963      * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
8964      * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
8965      * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
8966      * StringUtils.unwrap("A", "#")           = "A"
8967      * StringUtils.unwrap("#A", "#")          = "#A"
8968      * StringUtils.unwrap("A#", "#")          = "A#"
8969      * </pre>
8970      *
8971      * @param str       the String to be unwrapped, can be null.
8972      * @param wrapToken the String used to unwrap.
8973      * @return unwrapped String or the original string if it is not quoted properly with the wrapToken.
8974      * @since 3.6
8975      */
8976     public static String unwrap(final String str, final String wrapToken) {
8977         if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
8978             return str;
8979         }
8980         if (Strings.CS.startsWith(str, wrapToken) && Strings.CS.endsWith(str, wrapToken)) {
8981             return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
8982         }
8983         return str;
8984     }
8985 
8986     /**
8987      * Converts a String to upper case as per {@link String#toUpperCase()}.
8988      *
8989      * <p>
8990      * A {@code null} input String returns {@code null}.
8991      * </p>
8992      *
8993      * <pre>
8994      * StringUtils.upperCase(null)  = null
8995      * StringUtils.upperCase("")    = ""
8996      * StringUtils.upperCase("aBc") = "ABC"
8997      * </pre>
8998      *
8999      * <p>
9000      * <strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()}, the result of this method is affected by the current locale.
9001      * For platform-independent case transformations, the method {@link #upperCase(String, Locale)} should be used with a specific locale (e.g.
9002      * {@link Locale#ENGLISH}).
9003      * </p>
9004      *
9005      * @param str the String to upper case, may be null.
9006      * @return the upper-cased String, {@code null} if null String input.
9007      */
9008     public static String upperCase(final String str) {
9009         if (str == null) {
9010             return null;
9011         }
9012         return str.toUpperCase();
9013     }
9014 
9015     /**
9016      * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9017      *
9018      * <p>
9019      * A {@code null} input String returns {@code null}.
9020      * </p>
9021      *
9022      * <pre>
9023      * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9024      * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9025      * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9026      * </pre>
9027      *
9028      * @param str    the String to upper case, may be null.
9029      * @param locale the locale that defines the case transformation rules, must not be null.
9030      * @return the upper-cased String, {@code null} if null String input.
9031      * @since 2.5
9032      */
9033     public static String upperCase(final String str, final Locale locale) {
9034         if (str == null) {
9035             return null;
9036         }
9037         return str.toUpperCase(LocaleUtils.toLocale(locale));
9038     }
9039 
9040     /**
9041      * Returns the string representation of the {@code char} array or null.
9042      *
9043      * @param value the character array.
9044      * @return a String or null.
9045      * @see String#valueOf(char[])
9046      * @since 3.9
9047      */
9048     public static String valueOf(final char[] value) {
9049         return value == null ? null : String.valueOf(value);
9050     }
9051 
9052     /**
9053      * Wraps a string with a char.
9054      *
9055      * <pre>
9056      * StringUtils.wrap(null, *)        = null
9057      * StringUtils.wrap("", *)          = ""
9058      * StringUtils.wrap("ab", '\0')     = "ab"
9059      * StringUtils.wrap("ab", 'x')      = "xabx"
9060      * StringUtils.wrap("ab", '\'')     = "'ab'"
9061      * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9062      * </pre>
9063      *
9064      * @param str      the string to be wrapped, may be {@code null}.
9065      * @param wrapWith the char that will wrap {@code str}.
9066      * @return the wrapped string, or {@code null} if {@code str == null}.
9067      * @since 3.4
9068      */
9069     public static String wrap(final String str, final char wrapWith) {
9070         if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9071             return str;
9072         }
9073         return wrapWith + str + wrapWith;
9074     }
9075 
9076     /**
9077      * Wraps a String with another String.
9078      *
9079      * <p>
9080      * A {@code null} input String returns {@code null}.
9081      * </p>
9082      *
9083      * <pre>
9084      * StringUtils.wrap(null, *)         = null
9085      * StringUtils.wrap("", *)           = ""
9086      * StringUtils.wrap("ab", null)      = "ab"
9087      * StringUtils.wrap("ab", "x")       = "xabx"
9088      * StringUtils.wrap("ab", "\"")      = "\"ab\""
9089      * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9090      * StringUtils.wrap("ab", "'")       = "'ab'"
9091      * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9092      * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9093      * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9094      * </pre>
9095      *
9096      * @param str      the String to be wrapper, may be null.
9097      * @param wrapWith the String that will wrap str.
9098      * @return wrapped String, {@code null} if null String input.
9099      * @since 3.4
9100      */
9101     public static String wrap(final String str, final String wrapWith) {
9102         if (isEmpty(str) || isEmpty(wrapWith)) {
9103             return str;
9104         }
9105         return wrapWith.concat(str).concat(wrapWith);
9106     }
9107 
9108     /**
9109      * Wraps a string with a char if that char is missing from the start or end of the given string.
9110      *
9111      * <p>
9112      * A new {@link String} will not be created if {@code str} is already wrapped.
9113      * </p>
9114      *
9115      * <pre>
9116      * StringUtils.wrapIfMissing(null, *)        = null
9117      * StringUtils.wrapIfMissing("", *)          = ""
9118      * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9119      * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9120      * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9121      * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9122      * StringUtils.wrapIfMissing("/", '/')  = "/"
9123      * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9124      * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9125      * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9126      * </pre>
9127      *
9128      * @param str      the string to be wrapped, may be {@code null}.
9129      * @param wrapWith the char that will wrap {@code str}.
9130      * @return the wrapped string, or {@code null} if {@code str == null}.
9131      * @since 3.5
9132      */
9133     public static String wrapIfMissing(final String str, final char wrapWith) {
9134         if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9135             return str;
9136         }
9137         final boolean wrapStart = str.charAt(0) != wrapWith;
9138         final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9139         if (!wrapStart && !wrapEnd) {
9140             return str;
9141         }
9142         final StringBuilder builder = new StringBuilder(str.length() + 2);
9143         if (wrapStart) {
9144             builder.append(wrapWith);
9145         }
9146         builder.append(str);
9147         if (wrapEnd) {
9148             builder.append(wrapWith);
9149         }
9150         return builder.toString();
9151     }
9152 
9153     /**
9154      * Wraps a string with a string if that string is missing from the start or end of the given string.
9155      *
9156      * <p>
9157      * A new {@link String} will not be created if {@code str} is already wrapped.
9158      * </p>
9159      *
9160      * <pre>
9161      * StringUtils.wrapIfMissing(null, *)         = null
9162      * StringUtils.wrapIfMissing("", *)           = ""
9163      * StringUtils.wrapIfMissing("ab", null)      = "ab"
9164      * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9165      * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9166      * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9167      * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9168      * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9169      * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9170      * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9171      * StringUtils.wrapIfMissing("/", "/")  = "/"
9172      * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9173      * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9174      * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9175      * </pre>
9176      *
9177      * @param str      the string to be wrapped, may be {@code null}.
9178      * @param wrapWith the string that will wrap {@code str}.
9179      * @return the wrapped string, or {@code null} if {@code str == null}.
9180      * @since 3.5
9181      */
9182     public static String wrapIfMissing(final String str, final String wrapWith) {
9183         if (isEmpty(str) || isEmpty(wrapWith)) {
9184             return str;
9185         }
9186         final boolean wrapStart = !str.startsWith(wrapWith);
9187         final boolean wrapEnd = !str.endsWith(wrapWith);
9188         if (!wrapStart && !wrapEnd) {
9189             return str;
9190         }
9191         final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9192         if (wrapStart) {
9193             builder.append(wrapWith);
9194         }
9195         builder.append(str);
9196         if (wrapEnd) {
9197             builder.append(wrapWith);
9198         }
9199         return builder.toString();
9200     }
9201 
9202     /**
9203      * {@link StringUtils} instances should NOT be constructed in standard programming. Instead, the class should be used as {@code StringUtils.trim(" foo ");}.
9204      *
9205      * <p>
9206      * This constructor is public to permit tools that require a JavaBean instance to operate.
9207      * </p>
9208      *
9209      * @deprecated TODO Make private in 4.0.
9210      */
9211     @Deprecated
9212     public StringUtils() {
9213         // empty
9214     }
9215 
9216 }