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