View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3;
18  
19  import java.io.UnsupportedEncodingException;
20  import java.nio.charset.Charset;
21  import java.text.Normalizer;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.HashSet;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Objects;
29  import java.util.Set;
30  import java.util.function.Supplier;
31  import java.util.regex.Pattern;
32  
33  import org.apache.commons.lang3.function.Suppliers;
34  import org.apache.commons.lang3.function.ToBooleanBiFunction;
35  import org.apache.commons.lang3.stream.LangCollectors;
36  import org.apache.commons.lang3.stream.Streams;
37  
38  /**
39   * Operations on {@link java.lang.String} that are
40   * {@code null} safe.
41   *
42   * <ul>
43   *  <li><b>IsEmpty/IsBlank</b>
44   *      - checks if a String contains text</li>
45   *  <li><b>Trim/Strip</b>
46   *      - removes leading and trailing whitespace</li>
47   *  <li><b>Equals/Compare</b>
48   *      - compares two strings in a null-safe manner</li>
49   *  <li><b>startsWith</b>
50   *      - check if a String starts with a prefix in a null-safe manner</li>
51   *  <li><b>endsWith</b>
52   *      - check if a String ends with a suffix in a null-safe manner</li>
53   *  <li><b>IndexOf/LastIndexOf/Contains</b>
54   *      - null-safe index-of checks
55   *  <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
56   *      - index-of any of a set of Strings</li>
57   *  <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
58   *      - checks if String contains only/none/any of these characters</li>
59   *  <li><b>Substring/Left/Right/Mid</b>
60   *      - null-safe substring extractions</li>
61   *  <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
62   *      - substring extraction relative to other strings</li>
63   *  <li><b>Split/Join</b>
64   *      - splits a String into an array of substrings and vice versa</li>
65   *  <li><b>Remove/Delete</b>
66   *      - removes part of a String</li>
67   *  <li><b>Replace/Overlay</b>
68   *      - Searches a String and replaces one String with another</li>
69   *  <li><b>Chomp/Chop</b>
70   *      - removes the last part of a String</li>
71   *  <li><b>AppendIfMissing</b>
72   *      - appends a suffix to the end of the String if not present</li>
73   *  <li><b>PrependIfMissing</b>
74   *      - prepends a prefix to the start of the String if not present</li>
75   *  <li><b>LeftPad/RightPad/Center/Repeat</b>
76   *      - pads a String</li>
77   *  <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
78   *      - changes the case of a String</li>
79   *  <li><b>CountMatches</b>
80   *      - counts the number of occurrences of one String in another</li>
81   *  <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
82   *      - checks the characters in a String</li>
83   *  <li><b>DefaultString</b>
84   *      - protects against a null input String</li>
85   *  <li><b>Rotate</b>
86   *      - rotate (circular shift) a String</li>
87   *  <li><b>Reverse/ReverseDelimited</b>
88   *      - reverses a String</li>
89   *  <li><b>Abbreviate</b>
90   *      - abbreviates a string using ellipses or another given String</li>
91   *  <li><b>Difference</b>
92   *      - compares Strings and reports on their differences</li>
93   *  <li><b>LevenshteinDistance</b>
94   *      - the number of changes needed to change one String into another</li>
95   * </ul>
96   *
97   * <p>The {@link StringUtils} class defines certain words related to
98   * String handling.</p>
99   *
100  * <ul>
101  *  <li>null - {@code null}</li>
102  *  <li>empty - a zero-length string ({@code ""})</li>
103  *  <li>space - the space character ({@code ' '}, char 32)</li>
104  *  <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
105  *  <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
106  * </ul>
107  *
108  * <p>{@link StringUtils} handles {@code null} input Strings quietly.
109  * That is to say that a {@code null} input will return {@code null}.
110  * Where a {@code boolean} or {@code int} is being returned
111  * details vary by method.</p>
112  *
113  * <p>A side effect of the {@code null} handling is that a
114  * {@link NullPointerException} should be considered a bug in
115  * {@link StringUtils}.</p>
116  *
117  * <p>Methods in this class include sample code in their Javadoc comments to explain their operation.
118  * The symbol {@code *} is used to indicate any input including {@code null}.</p>
119  *
120  * <p>#ThreadSafe#</p>
121  * @see String
122  * @since 1.0
123  */
124 //@Immutable
125 public class StringUtils {
126 
127     // Performance testing notes (JDK 1.4, Jul03, scolebourne)
128     // Whitespace:
129     // Character.isWhitespace() is faster than WHITESPACE.indexOf()
130     // where WHITESPACE is a string of all whitespace characters
131     //
132     // Character access:
133     // String.charAt(n) versus toCharArray(), then array[n]
134     // String.charAt(n) is about 15% worse for a 10K string
135     // They are about equal for a length 50 string
136     // String.charAt(n) is about 4 times better for a length 3 string
137     // String.charAt(n) is best bet overall
138     //
139     // Append:
140     // String.concat about twice as fast as StringBuffer.append
141     // (not sure who tested this)
142 
143     /**
144      * A String for a space character.
145      *
146      * @since 3.2
147      */
148     public static final String SPACE = " ";
149 
150     /**
151      * The empty String {@code ""}.
152      * @since 2.0
153      */
154     public static final String EMPTY = "";
155 
156     /**
157      * A String for linefeed LF ("\n").
158      *
159      * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
160      *      for Character and String Literals</a>
161      * @since 3.2
162      */
163     public static final String LF = "\n";
164 
165     /**
166      * A String for carriage return CR ("\r").
167      *
168      * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
169      *      for Character and String Literals</a>
170      * @since 3.2
171      */
172     public static final String CR = "\r";
173 
174     /**
175      * Represents a failed index search.
176      * @since 2.1
177      */
178     public static final int INDEX_NOT_FOUND = -1;
179 
180     /**
181      * The maximum size to which the padding constant(s) can expand.
182      */
183     private static final int PAD_LIMIT = 8192;
184 
185     /**
186      * Pattern used in {@link #stripAccents(String)}.
187      */
188     private static final Pattern STRIP_ACCENTS_PATTERN = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); //$NON-NLS-1$
189 
190     /**
191      * Abbreviates a String using ellipses. This will turn
192      * "Now is the time for all good men" into "Now is the time for..."
193      *
194      * <p>Specifically:</p>
195      * <ul>
196      *   <li>If the number of characters in {@code str} is less than or equal to
197      *       {@code maxWidth}, return {@code str}.</li>
198      *   <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
199      *   <li>If {@code maxWidth} is less than {@code 4}, throw an
200      *       {@link IllegalArgumentException}.</li>
201      *   <li>In no case will it return a String of length greater than
202      *       {@code maxWidth}.</li>
203      * </ul>
204      *
205      * <pre>
206      * StringUtils.abbreviate(null, *)      = null
207      * StringUtils.abbreviate("", 4)        = ""
208      * StringUtils.abbreviate("abcdefg", 6) = "abc..."
209      * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
210      * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
211      * StringUtils.abbreviate("abcdefg", 4) = "a..."
212      * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
213      * </pre>
214      *
215      * @param str  the String to check, may be null
216      * @param maxWidth  maximum length of result String, must be at least 4
217      * @return abbreviated String, {@code null} if null String input
218      * @throws IllegalArgumentException if the width is too small
219      * @since 2.0
220      */
221     public static String abbreviate(final String str, final int maxWidth) {
222         return abbreviate(str, "...", 0, maxWidth);
223     }
224 
225     /**
226      * Abbreviates a String using ellipses. This will turn
227      * "Now is the time for all good men" into "...is the time for..."
228      *
229      * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
230      * a "left edge" offset.  Note that this left edge is not necessarily going to
231      * be the leftmost character in the result, or the first character following the
232      * ellipses, but it will appear somewhere in the result.
233      *
234      * <p>In no case will it return a String of length greater than
235      * {@code maxWidth}.</p>
236      *
237      * <pre>
238      * StringUtils.abbreviate(null, *, *)                = null
239      * StringUtils.abbreviate("", 0, 4)                  = ""
240      * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
241      * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
242      * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
243      * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
244      * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
245      * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
246      * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
247      * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
248      * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
249      * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
250      * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
251      * </pre>
252      *
253      * @param str  the String to check, may be null
254      * @param offset  left edge of source String
255      * @param maxWidth  maximum length of result String, must be at least 4
256      * @return abbreviated String, {@code null} if null String input
257      * @throws IllegalArgumentException if the width is too small
258      * @since 2.0
259      */
260     public static String abbreviate(final String str, final int offset, final int maxWidth) {
261         return abbreviate(str, "...", offset, maxWidth);
262     }
263 
264     /**
265      * Abbreviates a String using another given String as replacement marker. This will turn
266      * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
267      * as the replacement marker.
268      *
269      * <p>Specifically:</p>
270      * <ul>
271      *   <li>If the number of characters in {@code str} is less than or equal to
272      *       {@code maxWidth}, return {@code str}.</li>
273      *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
274      *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
275      *       {@link IllegalArgumentException}.</li>
276      *   <li>In no case will it return a String of length greater than
277      *       {@code maxWidth}.</li>
278      * </ul>
279      *
280      * <pre>
281      * StringUtils.abbreviate(null, "...", *)      = null
282      * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
283      * StringUtils.abbreviate("", "...", 4)        = ""
284      * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
285      * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
286      * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
287      * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
288      * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
289      * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
290      * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
291      * </pre>
292      *
293      * @param str  the String to check, may be null
294      * @param abbrevMarker  the String used as replacement marker
295      * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length + 1}
296      * @return abbreviated String, {@code null} if null String input
297      * @throws IllegalArgumentException if the width is too small
298      * @since 3.6
299      */
300     public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
301         return abbreviate(str, abbrevMarker, 0, maxWidth);
302     }
303     /**
304      * Abbreviates a String using a given replacement marker. This will turn
305      * "Now is the time for all good men" into "...is the time for..." if "..." was defined
306      * as the replacement marker.
307      *
308      * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
309      * a "left edge" offset.  Note that this left edge is not necessarily going to
310      * be the leftmost character in the result, or the first character following the
311      * replacement marker, but it will appear somewhere in the result.
312      *
313      * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
314      *
315      * <pre>
316      * StringUtils.abbreviate(null, null, *, *)                 = null
317      * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
318      * StringUtils.abbreviate("", "...", 0, 4)                  = ""
319      * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
320      * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
321      * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
322      * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
323      * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
324      * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
325      * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
326      * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
327      * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
328      * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
329      * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
330      * </pre>
331      *
332      * @param str  the String to check, may be null
333      * @param abbrevMarker  the String used as replacement marker
334      * @param offset  left edge of source String
335      * @param maxWidth  maximum length of result String, must be at least 4
336      * @return abbreviated String, {@code null} if null String input
337      * @throws IllegalArgumentException if the width is too small
338      * @since 3.6
339      */
340     public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
341         if (isNotEmpty(str) && EMPTY.equals(abbrevMarker) && maxWidth > 0) {
342             return substring(str, 0, maxWidth);
343         }
344         if (isAnyEmpty(str, abbrevMarker)) {
345             return str;
346         }
347         final int abbrevMarkerLength = abbrevMarker.length();
348         final int minAbbrevWidth = abbrevMarkerLength + 1;
349         final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
350 
351         if (maxWidth < minAbbrevWidth) {
352             throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
353         }
354         final int strLen = str.length();
355         if (strLen <= maxWidth) {
356             return str;
357         }
358         if (offset > strLen) {
359             offset = strLen;
360         }
361         if (strLen - offset < maxWidth - abbrevMarkerLength) {
362             offset = strLen - (maxWidth - abbrevMarkerLength);
363         }
364         if (offset <= abbrevMarkerLength+1) {
365             return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
366         }
367         if (maxWidth < minAbbrevWidthOffset) {
368             throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
369         }
370         if (offset + maxWidth - abbrevMarkerLength < strLen) {
371             return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
372         }
373         return abbrevMarker + str.substring(strLen - (maxWidth - abbrevMarkerLength));
374     }
375 
376     /**
377      * Abbreviates a String to the length passed, replacing the middle characters with the supplied
378      * replacement String.
379      *
380      * <p>This abbreviation only occurs if the following criteria is met:</p>
381      * <ul>
382      * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
383      * <li>The length to truncate to is less than the length of the supplied String</li>
384      * <li>The length to truncate to is greater than 0</li>
385      * <li>The abbreviated String will have enough room for the length supplied replacement String
386      * and the first and last characters of the supplied String for abbreviation</li>
387      * </ul>
388      * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
389      * </p>
390      *
391      * <pre>
392      * StringUtils.abbreviateMiddle(null, null, 0)      = null
393      * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
394      * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
395      * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
396      * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
397      * </pre>
398      *
399      * @param str  the String to abbreviate, may be null
400      * @param middle the String to replace the middle characters with, may be null
401      * @param length the length to abbreviate {@code str} to.
402      * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
403      * @since 2.5
404      */
405     public static String abbreviateMiddle(final String str, final String middle, final int length) {
406         if (isAnyEmpty(str, middle) || length >= str.length() || length < middle.length()+2) {
407             return str;
408         }
409 
410         final int targetSting = length-middle.length();
411         final int startOffset = targetSting/2+targetSting%2;
412         final int endOffset = str.length()-targetSting/2;
413 
414         return str.substring(0, startOffset) +
415             middle +
416             str.substring(endOffset);
417     }
418 
419     /**
420      * Appends the suffix to the end of the string if the string does not
421      * already end with the suffix.
422      *
423      * @param str The string.
424      * @param suffix The suffix to append to the end of the string.
425      * @param ignoreCase Indicates whether the compare should ignore case.
426      * @param suffixes Additional suffixes that are valid terminators (optional).
427      *
428      * @return A new String if suffix was appended, the same string otherwise.
429      */
430     private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
431         if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
432             return str;
433         }
434         if (ArrayUtils.isNotEmpty(suffixes)) {
435             for (final CharSequence s : suffixes) {
436                 if (endsWith(str, s, ignoreCase)) {
437                     return str;
438                 }
439             }
440         }
441         return str + suffix.toString();
442     }
443 
444     /**
445      * Appends the suffix to the end of the string if the string does not
446      * already end with any of the suffixes.
447      *
448      * <pre>
449      * StringUtils.appendIfMissing(null, null) = null
450      * StringUtils.appendIfMissing("abc", null) = "abc"
451      * StringUtils.appendIfMissing("", "xyz") = "xyz"
452      * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
453      * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
454      * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
455      * </pre>
456      * <p>With additional suffixes,</p>
457      * <pre>
458      * StringUtils.appendIfMissing(null, null, null) = null
459      * StringUtils.appendIfMissing("abc", null, null) = "abc"
460      * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
461      * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
462      * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
463      * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
464      * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
465      * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
466      * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
467      * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
468      * </pre>
469      *
470      * @param str The string.
471      * @param suffix The suffix to append to the end of the string.
472      * @param suffixes Additional suffixes that are valid terminators.
473      *
474      * @return A new String if suffix was appended, the same string otherwise.
475      *
476      * @since 3.2
477      */
478     public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
479         return appendIfMissing(str, suffix, false, suffixes);
480     }
481 
482     /**
483      * Appends the suffix to the end of the string if the string does not
484      * already end, case-insensitive, with any of the suffixes.
485      *
486      * <pre>
487      * StringUtils.appendIfMissingIgnoreCase(null, null) = null
488      * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
489      * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
490      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
491      * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
492      * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
493      * </pre>
494      * <p>With additional suffixes,</p>
495      * <pre>
496      * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
497      * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
498      * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
499      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
500      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
501      * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "abcxyz"
502      * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
503      * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
504      * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
505      * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
506      * </pre>
507      *
508      * @param str The string.
509      * @param suffix The suffix to append to the end of the string.
510      * @param suffixes Additional suffixes that are valid terminators.
511      *
512      * @return A new String if suffix was appended, the same string otherwise.
513      *
514      * @since 3.2
515      */
516     public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
517         return appendIfMissing(str, suffix, true, suffixes);
518     }
519 
520     /**
521      * Capitalizes a String changing the first character to title case as
522      * per {@link Character#toTitleCase(int)}. No other characters are changed.
523      *
524      * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#capitalize(String)}.
525      * A {@code null} input String returns {@code null}.</p>
526      *
527      * <pre>
528      * StringUtils.capitalize(null)  = null
529      * StringUtils.capitalize("")    = ""
530      * StringUtils.capitalize("cat") = "Cat"
531      * StringUtils.capitalize("cAt") = "CAt"
532      * StringUtils.capitalize("'cat'") = "'cat'"
533      * </pre>
534      *
535      * @param str the String to capitalize, may be null
536      * @return the capitalized String, {@code null} if null String input
537      * @see org.apache.commons.text.WordUtils#capitalize(String)
538      * @see #uncapitalize(String)
539      * @since 2.0
540      */
541     public static String capitalize(final String str) {
542         final int strLen = length(str);
543         if (strLen == 0) {
544             return str;
545         }
546 
547         final int firstCodepoint = str.codePointAt(0);
548         final int newCodePoint = Character.toTitleCase(firstCodepoint);
549         if (firstCodepoint == newCodePoint) {
550             // already capitalized
551             return str;
552         }
553 
554         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
555         int outOffset = 0;
556         newCodePoints[outOffset++] = newCodePoint; // copy the first code point
557         for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
558             final int codePoint = str.codePointAt(inOffset);
559             newCodePoints[outOffset++] = codePoint; // copy the remaining ones
560             inOffset += Character.charCount(codePoint);
561          }
562         return new String(newCodePoints, 0, outOffset);
563     }
564 
565     /**
566      * Centers a String in a larger String of size {@code size}
567      * using the space character (' ').
568      *
569      * <p>If the size is less than the String length, the original String is returned.
570      * A {@code null} String returns {@code null}.
571      * A negative size is treated as zero.</p>
572      *
573      * <p>Equivalent to {@code center(str, size, " ")}.</p>
574      *
575      * <pre>
576      * StringUtils.center(null, *)   = null
577      * StringUtils.center("", 4)     = "    "
578      * StringUtils.center("ab", -1)  = "ab"
579      * StringUtils.center("ab", 4)   = " ab "
580      * StringUtils.center("abcd", 2) = "abcd"
581      * StringUtils.center("a", 4)    = " a  "
582      * </pre>
583      *
584      * @param str  the String to center, may be null
585      * @param size  the int size of new String, negative treated as zero
586      * @return centered String, {@code null} if null String input
587      */
588     public static String center(final String str, final int size) {
589         return center(str, size, ' ');
590     }
591 
592     /**
593      * Centers a String in a larger String of size {@code size}.
594      * Uses a supplied character as the value to pad the String with.
595      *
596      * <p>If the size is less than the String length, the String is returned.
597      * A {@code null} String returns {@code null}.
598      * A negative size is treated as zero.</p>
599      *
600      * <pre>
601      * StringUtils.center(null, *, *)     = null
602      * StringUtils.center("", 4, ' ')     = "    "
603      * StringUtils.center("ab", -1, ' ')  = "ab"
604      * StringUtils.center("ab", 4, ' ')   = " ab "
605      * StringUtils.center("abcd", 2, ' ') = "abcd"
606      * StringUtils.center("a", 4, ' ')    = " a  "
607      * StringUtils.center("a", 4, 'y')    = "yayy"
608      * </pre>
609      *
610      * @param str  the String to center, may be null
611      * @param size  the int size of new String, negative treated as zero
612      * @param padChar  the character to pad the new String with
613      * @return centered String, {@code null} if null String input
614      * @since 2.0
615      */
616     public static String center(String str, final int size, final char padChar) {
617         if (str == null || size <= 0) {
618             return str;
619         }
620         final int strLen = str.length();
621         final int pads = size - strLen;
622         if (pads <= 0) {
623             return str;
624         }
625         str = leftPad(str, strLen + pads / 2, padChar);
626         str = rightPad(str, size, padChar);
627         return str;
628     }
629 
630     /**
631      * Centers a String in a larger String of size {@code size}.
632      * Uses a supplied String as the value to pad the String with.
633      *
634      * <p>If the size is less than the String length, the String is returned.
635      * A {@code null} String returns {@code null}.
636      * A negative size is treated as zero.</p>
637      *
638      * <pre>
639      * StringUtils.center(null, *, *)     = null
640      * StringUtils.center("", 4, " ")     = "    "
641      * StringUtils.center("ab", -1, " ")  = "ab"
642      * StringUtils.center("ab", 4, " ")   = " ab "
643      * StringUtils.center("abcd", 2, " ") = "abcd"
644      * StringUtils.center("a", 4, " ")    = " a  "
645      * StringUtils.center("a", 4, "yz")   = "yayz"
646      * StringUtils.center("abc", 7, null) = "  abc  "
647      * StringUtils.center("abc", 7, "")   = "  abc  "
648      * </pre>
649      *
650      * @param str  the String to center, may be null
651      * @param size  the int size of new String, negative treated as zero
652      * @param padStr  the String to pad the new String with, must not be null or empty
653      * @return centered String, {@code null} if null String input
654      * @throws IllegalArgumentException if padStr is {@code null} or empty
655      */
656     public static String center(String str, final int size, String padStr) {
657         if (str == null || size <= 0) {
658             return str;
659         }
660         if (isEmpty(padStr)) {
661             padStr = SPACE;
662         }
663         final int strLen = str.length();
664         final int pads = size - strLen;
665         if (pads <= 0) {
666             return str;
667         }
668         str = leftPad(str, strLen + pads / 2, padStr);
669         str = rightPad(str, size, padStr);
670         return str;
671     }
672 
673     /**
674      * Removes one newline from end of a String if it's there,
675      * otherwise leave it alone.  A newline is &quot;{@code \n}&quot;,
676      * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.
677      *
678      * <p>NOTE: This method changed in 2.0.
679      * It now more closely matches Perl chomp.</p>
680      *
681      * <pre>
682      * StringUtils.chomp(null)          = null
683      * StringUtils.chomp("")            = ""
684      * StringUtils.chomp("abc \r")      = "abc "
685      * StringUtils.chomp("abc\n")       = "abc"
686      * StringUtils.chomp("abc\r\n")     = "abc"
687      * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
688      * StringUtils.chomp("abc\n\r")     = "abc\n"
689      * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
690      * StringUtils.chomp("\r")          = ""
691      * StringUtils.chomp("\n")          = ""
692      * StringUtils.chomp("\r\n")        = ""
693      * </pre>
694      *
695      * @param str  the String to chomp a newline from, may be null
696      * @return String without newline, {@code null} if null String input
697      */
698     public static String chomp(final String str) {
699         if (isEmpty(str)) {
700             return str;
701         }
702 
703         if (str.length() == 1) {
704             final char ch = str.charAt(0);
705             if (ch == CharUtils.CR || ch == CharUtils.LF) {
706                 return EMPTY;
707             }
708             return str;
709         }
710 
711         int lastIdx = str.length() - 1;
712         final char last = str.charAt(lastIdx);
713 
714         if (last == CharUtils.LF) {
715             if (str.charAt(lastIdx - 1) == CharUtils.CR) {
716                 lastIdx--;
717             }
718         } else if (last != CharUtils.CR) {
719             lastIdx++;
720         }
721         return str.substring(0, lastIdx);
722     }
723 
724     /**
725      * Removes {@code separator} from the end of
726      * {@code str} if it's there, otherwise leave it alone.
727      *
728      * <p>NOTE: This method changed in version 2.0.
729      * It now more closely matches Perl chomp.
730      * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
731      * This method uses {@link String#endsWith(String)}.</p>
732      *
733      * <pre>
734      * StringUtils.chomp(null, *)         = null
735      * StringUtils.chomp("", *)           = ""
736      * StringUtils.chomp("foobar", "bar") = "foo"
737      * StringUtils.chomp("foobar", "baz") = "foobar"
738      * StringUtils.chomp("foo", "foo")    = ""
739      * StringUtils.chomp("foo ", "foo")   = "foo "
740      * StringUtils.chomp(" foo", "foo")   = " "
741      * StringUtils.chomp("foo", "foooo")  = "foo"
742      * StringUtils.chomp("foo", "")       = "foo"
743      * StringUtils.chomp("foo", null)     = "foo"
744      * </pre>
745      *
746      * @param str  the String to chomp from, may be null
747      * @param separator  separator String, may be null
748      * @return String without trailing separator, {@code null} if null String input
749      * @deprecated This feature will be removed in Lang 4, use {@link StringUtils#removeEnd(String, String)} instead
750      */
751     @Deprecated
752     public static String chomp(final String str, final String separator) {
753         return removeEnd(str, separator);
754     }
755 
756     /**
757      * Remove the last character from a String.
758      *
759      * <p>If the String ends in {@code \r\n}, then remove both
760      * of them.</p>
761      *
762      * <pre>
763      * StringUtils.chop(null)          = null
764      * StringUtils.chop("")            = ""
765      * StringUtils.chop("abc \r")      = "abc "
766      * StringUtils.chop("abc\n")       = "abc"
767      * StringUtils.chop("abc\r\n")     = "abc"
768      * StringUtils.chop("abc")         = "ab"
769      * StringUtils.chop("abc\nabc")    = "abc\nab"
770      * StringUtils.chop("a")           = ""
771      * StringUtils.chop("\r")          = ""
772      * StringUtils.chop("\n")          = ""
773      * StringUtils.chop("\r\n")        = ""
774      * </pre>
775      *
776      * @param str  the String to chop last character from, may be null
777      * @return String without last character, {@code null} if null String input
778      */
779     public static String chop(final String str) {
780         if (str == null) {
781             return null;
782         }
783         final int strLen = str.length();
784         if (strLen < 2) {
785             return EMPTY;
786         }
787         final int lastIdx = strLen - 1;
788         final String ret = str.substring(0, lastIdx);
789         final char last = str.charAt(lastIdx);
790         if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
791             return ret.substring(0, lastIdx - 1);
792         }
793         return ret;
794     }
795 
796     /**
797      * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
798      * <ul>
799      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
800      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
801      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
802      * </ul>
803      *
804      * <p>This is a {@code null} safe version of :</p>
805      * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
806      *
807      * <p>{@code null} value is considered less than non-{@code null} value.
808      * Two {@code null} references are considered equal.</p>
809      *
810      * <pre>
811      * StringUtils.compare(null, null)   = 0
812      * StringUtils.compare(null , "a")   &lt; 0
813      * StringUtils.compare("a", null)    &gt; 0
814      * StringUtils.compare("abc", "abc") = 0
815      * StringUtils.compare("a", "b")     &lt; 0
816      * StringUtils.compare("b", "a")     &gt; 0
817      * StringUtils.compare("a", "B")     &gt; 0
818      * StringUtils.compare("ab", "abc")  &lt; 0
819      * </pre>
820      *
821      * @see #compare(String, String, boolean)
822      * @see String#compareTo(String)
823      * @param str1  the String to compare from
824      * @param str2  the String to compare to
825      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal or greater than {@code str2}
826      * @since 3.5
827      */
828     public static int compare(final String str1, final String str2) {
829         return compare(str1, str2, true);
830     }
831 
832     /**
833      * Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :
834      * <ul>
835      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
836      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
837      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
838      * </ul>
839      *
840      * <p>This is a {@code null} safe version of :</p>
841      * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
842      *
843      * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
844      * Two {@code null} references are considered equal.</p>
845      *
846      * <pre>
847      * StringUtils.compare(null, null, *)     = 0
848      * StringUtils.compare(null , "a", true)  &lt; 0
849      * StringUtils.compare(null , "a", false) &gt; 0
850      * StringUtils.compare("a", null, true)   &gt; 0
851      * StringUtils.compare("a", null, false)  &lt; 0
852      * StringUtils.compare("abc", "abc", *)   = 0
853      * StringUtils.compare("a", "b", *)       &lt; 0
854      * StringUtils.compare("b", "a", *)       &gt; 0
855      * StringUtils.compare("a", "B", *)       &gt; 0
856      * StringUtils.compare("ab", "abc", *)    &lt; 0
857      * </pre>
858      *
859      * @see String#compareTo(String)
860      * @param str1  the String to compare from
861      * @param str2  the String to compare to
862      * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
863      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
864      * @since 3.5
865      */
866     public static int compare(final String str1, final String str2, final boolean nullIsLess) {
867         if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
868             return 0;
869         }
870         if (str1 == null) {
871             return nullIsLess ? -1 : 1;
872         }
873         if (str2 == null) {
874             return nullIsLess ? 1 : - 1;
875         }
876         return str1.compareTo(str2);
877     }
878 
879     /**
880      * Compare two Strings lexicographically, ignoring case differences,
881      * as per {@link String#compareToIgnoreCase(String)}, returning :
882      * <ul>
883      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
884      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
885      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
886      * </ul>
887      *
888      * <p>This is a {@code null} safe version of :</p>
889      * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
890      *
891      * <p>{@code null} value is considered less than non-{@code null} value.
892      * Two {@code null} references are considered equal.
893      * Comparison is case insensitive.</p>
894      *
895      * <pre>
896      * StringUtils.compareIgnoreCase(null, null)   = 0
897      * StringUtils.compareIgnoreCase(null , "a")   &lt; 0
898      * StringUtils.compareIgnoreCase("a", null)    &gt; 0
899      * StringUtils.compareIgnoreCase("abc", "abc") = 0
900      * StringUtils.compareIgnoreCase("abc", "ABC") = 0
901      * StringUtils.compareIgnoreCase("a", "b")     &lt; 0
902      * StringUtils.compareIgnoreCase("b", "a")     &gt; 0
903      * StringUtils.compareIgnoreCase("a", "B")     &lt; 0
904      * StringUtils.compareIgnoreCase("A", "b")     &lt; 0
905      * StringUtils.compareIgnoreCase("ab", "ABC")  &lt; 0
906      * </pre>
907      *
908      * @see #compareIgnoreCase(String, String, boolean)
909      * @see String#compareToIgnoreCase(String)
910      * @param str1  the String to compare from
911      * @param str2  the String to compare to
912      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
913      *          ignoring case differences.
914      * @since 3.5
915      */
916     public static int compareIgnoreCase(final String str1, final String str2) {
917         return compareIgnoreCase(str1, str2, true);
918     }
919 
920     /**
921      * Compare two Strings lexicographically, ignoring case differences,
922      * as per {@link String#compareToIgnoreCase(String)}, returning :
923      * <ul>
924      *  <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
925      *  <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
926      *  <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
927      * </ul>
928      *
929      * <p>This is a {@code null} safe version of :</p>
930      * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
931      *
932      * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
933      * Two {@code null} references are considered equal.
934      * Comparison is case insensitive.</p>
935      *
936      * <pre>
937      * StringUtils.compareIgnoreCase(null, null, *)     = 0
938      * StringUtils.compareIgnoreCase(null , "a", true)  &lt; 0
939      * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
940      * StringUtils.compareIgnoreCase("a", null, true)   &gt; 0
941      * StringUtils.compareIgnoreCase("a", null, false)  &lt; 0
942      * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
943      * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
944      * StringUtils.compareIgnoreCase("a", "b", *)       &lt; 0
945      * StringUtils.compareIgnoreCase("b", "a", *)       &gt; 0
946      * StringUtils.compareIgnoreCase("a", "B", *)       &lt; 0
947      * StringUtils.compareIgnoreCase("A", "b", *)       &lt; 0
948      * StringUtils.compareIgnoreCase("ab", "abc", *)    &lt; 0
949      * </pre>
950      *
951      * @see String#compareToIgnoreCase(String)
952      * @param str1  the String to compare from
953      * @param str2  the String to compare to
954      * @param nullIsLess  whether consider {@code null} value less than non-{@code null} value
955      * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
956      *          ignoring case differences.
957      * @since 3.5
958      */
959     public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
960         if (str1 == str2) { // NOSONARLINT this intentionally uses == to allow for both null
961             return 0;
962         }
963         if (str1 == null) {
964             return nullIsLess ? -1 : 1;
965         }
966         if (str2 == null) {
967             return nullIsLess ? 1 : - 1;
968         }
969         return str1.compareToIgnoreCase(str2);
970     }
971 
972     /**
973      * Checks if CharSequence contains a search CharSequence, handling {@code null}.
974      * This method uses {@link String#indexOf(String)} if possible.
975      *
976      * <p>A {@code null} CharSequence will return {@code false}.</p>
977      *
978      * <pre>
979      * StringUtils.contains(null, *)     = false
980      * StringUtils.contains(*, null)     = false
981      * StringUtils.contains("", "")      = true
982      * StringUtils.contains("abc", "")   = true
983      * StringUtils.contains("abc", "a")  = true
984      * StringUtils.contains("abc", "z")  = false
985      * </pre>
986      *
987      * @param seq  the CharSequence to check, may be null
988      * @param searchSeq  the CharSequence to find, may be null
989      * @return true if the CharSequence contains the search CharSequence,
990      *  false if not or {@code null} string input
991      * @since 2.0
992      * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
993      */
994     public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
995         if (seq == null || searchSeq == null) {
996             return false;
997         }
998         return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
999     }
1000 
1001     /**
1002      * Checks if CharSequence contains a search character, handling {@code null}.
1003      * This method uses {@link String#indexOf(int)} if possible.
1004      *
1005      * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1006      *
1007      * <pre>
1008      * StringUtils.contains(null, *)    = false
1009      * StringUtils.contains("", *)      = false
1010      * StringUtils.contains("abc", 'a') = true
1011      * StringUtils.contains("abc", 'z') = false
1012      * </pre>
1013      *
1014      * @param seq  the CharSequence to check, may be null
1015      * @param searchChar  the character to find
1016      * @return true if the CharSequence contains the search character,
1017      *  false if not or {@code null} string input
1018      * @since 2.0
1019      * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1020      */
1021     public static boolean contains(final CharSequence seq, final int searchChar) {
1022         if (isEmpty(seq)) {
1023             return false;
1024         }
1025         return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1026     }
1027 
1028     /**
1029      * Checks if the CharSequence contains any character in the given
1030      * set of characters.
1031      *
1032      * <p>A {@code null} CharSequence will return {@code false}.
1033      * A {@code null} or zero length search array will return {@code false}.</p>
1034      *
1035      * <pre>
1036      * StringUtils.containsAny(null, *)                  = false
1037      * StringUtils.containsAny("", *)                    = false
1038      * StringUtils.containsAny(*, null)                  = false
1039      * StringUtils.containsAny(*, [])                    = false
1040      * StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
1041      * StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
1042      * StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
1043      * StringUtils.containsAny("aba", ['z'])             = false
1044      * </pre>
1045      *
1046      * @param cs  the CharSequence to check, may be null
1047      * @param searchChars  the chars to search for, may be null
1048      * @return the {@code true} if any of the chars are found,
1049      * {@code false} if no match or null input
1050      * @since 2.4
1051      * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
1052      */
1053     public static boolean containsAny(final CharSequence cs, final char... searchChars) {
1054         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
1055             return false;
1056         }
1057         final int csLength = cs.length();
1058         final int searchLength = searchChars.length;
1059         final int csLast = csLength - 1;
1060         final int searchLast = searchLength - 1;
1061         for (int i = 0; i < csLength; i++) {
1062             final char ch = cs.charAt(i);
1063             for (int j = 0; j < searchLength; j++) {
1064                 if (searchChars[j] == ch) {
1065                     if (!Character.isHighSurrogate(ch)) {
1066                         // ch is in the Basic Multilingual Plane
1067                         return true;
1068                     }
1069                     if (j == searchLast) {
1070                         // missing low surrogate, fine, like String.indexOf(String)
1071                         return true;
1072                     }
1073                     if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1074                         return true;
1075                     }
1076                 }
1077             }
1078         }
1079         return false;
1080     }
1081 
1082     /**
1083      * Checks if the CharSequence contains any character in the given set of characters.
1084      *
1085      * <p>
1086      * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
1087      * {@code false}.
1088      * </p>
1089      *
1090      * <pre>
1091      * StringUtils.containsAny(null, *)               = false
1092      * StringUtils.containsAny("", *)                 = false
1093      * StringUtils.containsAny(*, null)               = false
1094      * StringUtils.containsAny(*, "")                 = false
1095      * StringUtils.containsAny("zzabyycdxx", "za")    = true
1096      * StringUtils.containsAny("zzabyycdxx", "by")    = true
1097      * StringUtils.containsAny("zzabyycdxx", "zy")    = true
1098      * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
1099      * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
1100      * StringUtils.containsAny("aba", "z")            = false
1101      * </pre>
1102      *
1103      * @param cs
1104      *            the CharSequence to check, may be null
1105      * @param searchChars
1106      *            the chars to search for, may be null
1107      * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
1108      * @since 2.4
1109      * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
1110      */
1111     public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
1112         if (searchChars == null) {
1113             return false;
1114         }
1115         return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
1116     }
1117 
1118     /**
1119      * Checks if the CharSequence contains any of the CharSequences in the given array.
1120      *
1121      * <p>
1122      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1123      * return {@code false}.
1124      * </p>
1125      *
1126      * <pre>
1127      * StringUtils.containsAny(null, *)            = false
1128      * StringUtils.containsAny("", *)              = false
1129      * StringUtils.containsAny(*, null)            = false
1130      * StringUtils.containsAny(*, [])              = false
1131      * StringUtils.containsAny("abcd", "ab", null) = true
1132      * StringUtils.containsAny("abcd", "ab", "cd") = true
1133      * StringUtils.containsAny("abc", "d", "abc")  = true
1134      * </pre>
1135      *
1136      * @param cs The CharSequence to check, may be null
1137      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1138      *        null as well.
1139      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1140      * @since 3.4
1141      */
1142     public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
1143         return containsAny(StringUtils::contains, cs, searchCharSequences);
1144     }
1145 
1146     /**
1147      * Checks if the CharSequence contains any of the CharSequences in the given array.
1148      *
1149      * <p>
1150      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1151      * return {@code false}.
1152      * </p>
1153      *
1154      * @param cs The CharSequence to check, may be null
1155      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1156      *        null as well.
1157      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1158      * @since 3.12.0
1159      */
1160     private static boolean containsAny(final ToBooleanBiFunction<CharSequence, CharSequence> test,
1161         final CharSequence cs, final CharSequence... searchCharSequences) {
1162         if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
1163             return false;
1164         }
1165         for (final CharSequence searchCharSequence : searchCharSequences) {
1166             if (test.applyAsBoolean(cs, searchCharSequence)) {
1167                 return true;
1168             }
1169         }
1170         return false;
1171     }
1172 
1173     /**
1174      * Checks if the CharSequence contains any of the CharSequences in the given array, ignoring case.
1175      *
1176      * <p>
1177      * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero length search array will
1178      * return {@code false}.
1179      * </p>
1180      *
1181      * <pre>
1182      * StringUtils.containsAny(null, *)            = false
1183      * StringUtils.containsAny("", *)              = false
1184      * StringUtils.containsAny(*, null)            = false
1185      * StringUtils.containsAny(*, [])              = false
1186      * StringUtils.containsAny("abcd", "ab", null) = true
1187      * StringUtils.containsAny("abcd", "ab", "cd") = true
1188      * StringUtils.containsAny("abc", "d", "abc")  = true
1189      * StringUtils.containsAny("abc", "D", "ABC")  = true
1190      * StringUtils.containsAny("ABC", "d", "abc")  = true
1191      * </pre>
1192      *
1193      * @param cs The CharSequence to check, may be null
1194      * @param searchCharSequences The array of CharSequences to search for, may be null. Individual CharSequences may be
1195      *        null as well.
1196      * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
1197      * @since 3.12.0
1198      */
1199     public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) {
1200         return containsAny(StringUtils::containsIgnoreCase, cs, searchCharSequences);
1201     }
1202 
1203     /**
1204      * Checks if CharSequence contains a search CharSequence irrespective of case,
1205      * handling {@code null}. Case-insensitivity is defined as by
1206      * {@link String#equalsIgnoreCase(String)}.
1207      *
1208      * <p>A {@code null} CharSequence will return {@code false}.
1209      *
1210      * <pre>
1211      * StringUtils.containsIgnoreCase(null, *) = false
1212      * StringUtils.containsIgnoreCase(*, null) = false
1213      * StringUtils.containsIgnoreCase("", "") = true
1214      * StringUtils.containsIgnoreCase("abc", "") = true
1215      * StringUtils.containsIgnoreCase("abc", "a") = true
1216      * StringUtils.containsIgnoreCase("abc", "z") = false
1217      * StringUtils.containsIgnoreCase("abc", "A") = true
1218      * StringUtils.containsIgnoreCase("abc", "Z") = false
1219      * </pre>
1220      *
1221      * @param str  the CharSequence to check, may be null
1222      * @param searchStr  the CharSequence to find, may be null
1223      * @return true if the CharSequence contains the search CharSequence irrespective of
1224      * case or false if not or {@code null} string input
1225      * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
1226      */
1227     public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1228         if (str == null || searchStr == null) {
1229             return false;
1230         }
1231         final int len = searchStr.length();
1232         final int max = str.length() - len;
1233         for (int i = 0; i <= max; i++) {
1234             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
1235                 return true;
1236             }
1237         }
1238         return false;
1239     }
1240 
1241     /**
1242      * Checks that the CharSequence does not contain certain characters.
1243      *
1244      * <p>A {@code null} CharSequence will return {@code true}.
1245      * A {@code null} invalid character array will return {@code true}.
1246      * An empty CharSequence (length()=0) always returns true.</p>
1247      *
1248      * <pre>
1249      * StringUtils.containsNone(null, *)       = true
1250      * StringUtils.containsNone(*, null)       = true
1251      * StringUtils.containsNone("", *)         = true
1252      * StringUtils.containsNone("ab", '')      = true
1253      * StringUtils.containsNone("abab", 'xyz') = true
1254      * StringUtils.containsNone("ab1", 'xyz')  = true
1255      * StringUtils.containsNone("abz", 'xyz')  = false
1256      * </pre>
1257      *
1258      * @param cs  the CharSequence to check, may be null
1259      * @param searchChars  an array of invalid chars, may be null
1260      * @return true if it contains none of the invalid chars, or is null
1261      * @since 2.0
1262      * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
1263      */
1264     public static boolean containsNone(final CharSequence cs, final char... searchChars) {
1265         if (cs == null || searchChars == null) {
1266             return true;
1267         }
1268         final int csLen = cs.length();
1269         final int csLast = csLen - 1;
1270         final int searchLen = searchChars.length;
1271         final int searchLast = searchLen - 1;
1272         for (int i = 0; i < csLen; i++) {
1273             final char ch = cs.charAt(i);
1274             for (int j = 0; j < searchLen; j++) {
1275                 if (searchChars[j] == ch) {
1276                     if (!Character.isHighSurrogate(ch)) {
1277                         // ch is in the Basic Multilingual Plane
1278                         return false;
1279                     }
1280                     if (j == searchLast) {
1281                         // missing low surrogate, fine, like String.indexOf(String)
1282                         return false;
1283                     }
1284                     if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
1285                         return false;
1286                     }
1287                 }
1288             }
1289         }
1290         return true;
1291     }
1292 
1293     /**
1294      * Checks that the CharSequence does not contain certain characters.
1295      *
1296      * <p>A {@code null} CharSequence will return {@code true}.
1297      * A {@code null} invalid character array will return {@code true}.
1298      * An empty String ("") always returns true.</p>
1299      *
1300      * <pre>
1301      * StringUtils.containsNone(null, *)       = true
1302      * StringUtils.containsNone(*, null)       = true
1303      * StringUtils.containsNone("", *)         = true
1304      * StringUtils.containsNone("ab", "")      = true
1305      * StringUtils.containsNone("abab", "xyz") = true
1306      * StringUtils.containsNone("ab1", "xyz")  = true
1307      * StringUtils.containsNone("abz", "xyz")  = false
1308      * </pre>
1309      *
1310      * @param cs  the CharSequence to check, may be null
1311      * @param invalidChars  a String of invalid chars, may be null
1312      * @return true if it contains none of the invalid chars, or is null
1313      * @since 2.0
1314      * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
1315      */
1316     public static boolean containsNone(final CharSequence cs, final String invalidChars) {
1317         if (invalidChars == null) {
1318             return true;
1319         }
1320         return containsNone(cs, invalidChars.toCharArray());
1321     }
1322 
1323     /**
1324      * Checks if the CharSequence contains only certain characters.
1325      *
1326      * <p>A {@code null} CharSequence will return {@code false}.
1327      * A {@code null} valid character array will return {@code false}.
1328      * An empty CharSequence (length()=0) always returns {@code true}.</p>
1329      *
1330      * <pre>
1331      * StringUtils.containsOnly(null, *)       = false
1332      * StringUtils.containsOnly(*, null)       = false
1333      * StringUtils.containsOnly("", *)         = true
1334      * StringUtils.containsOnly("ab", '')      = false
1335      * StringUtils.containsOnly("abab", 'abc') = true
1336      * StringUtils.containsOnly("ab1", 'abc')  = false
1337      * StringUtils.containsOnly("abz", 'abc')  = false
1338      * </pre>
1339      *
1340      * @param cs  the String to check, may be null
1341      * @param valid  an array of valid chars, may be null
1342      * @return true if it only contains valid chars and is non-null
1343      * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
1344      */
1345     public static boolean containsOnly(final CharSequence cs, final char... valid) {
1346         // All these pre-checks are to maintain API with an older version
1347         if (valid == null || cs == null) {
1348             return false;
1349         }
1350         if (cs.length() == 0) {
1351             return true;
1352         }
1353         if (valid.length == 0) {
1354             return false;
1355         }
1356         return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
1357     }
1358 
1359     /**
1360      * Checks if the CharSequence contains only certain characters.
1361      *
1362      * <p>A {@code null} CharSequence will return {@code false}.
1363      * A {@code null} valid character String will return {@code false}.
1364      * An empty String (length()=0) always returns {@code true}.</p>
1365      *
1366      * <pre>
1367      * StringUtils.containsOnly(null, *)       = false
1368      * StringUtils.containsOnly(*, null)       = false
1369      * StringUtils.containsOnly("", *)         = true
1370      * StringUtils.containsOnly("ab", "")      = false
1371      * StringUtils.containsOnly("abab", "abc") = true
1372      * StringUtils.containsOnly("ab1", "abc")  = false
1373      * StringUtils.containsOnly("abz", "abc")  = false
1374      * </pre>
1375      *
1376      * @param cs  the CharSequence to check, may be null
1377      * @param validChars  a String of valid chars, may be null
1378      * @return true if it only contains valid chars and is non-null
1379      * @since 2.0
1380      * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
1381      */
1382     public static boolean containsOnly(final CharSequence cs, final String validChars) {
1383         if (cs == null || validChars == null) {
1384             return false;
1385         }
1386         return containsOnly(cs, validChars.toCharArray());
1387     }
1388 
1389     /**
1390      * Check whether the given CharSequence contains any whitespace characters.
1391      *
1392      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1393      *
1394      * @param seq the CharSequence to check (may be {@code null})
1395      * @return {@code true} if the CharSequence is not empty and
1396      * contains at least 1 (breaking) whitespace character
1397      * @since 3.0
1398      */
1399     // From org.springframework.util.StringUtils, under Apache License 2.0
1400     public static boolean containsWhitespace(final CharSequence seq) {
1401         if (isEmpty(seq)) {
1402             return false;
1403         }
1404         final int strLen = seq.length();
1405         for (int i = 0; i < strLen; i++) {
1406             if (Character.isWhitespace(seq.charAt(i))) {
1407                 return true;
1408             }
1409         }
1410         return false;
1411     }
1412 
1413     private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
1414         for (int i = 0; i < decomposed.length(); i++) {
1415             if (decomposed.charAt(i) == '\u0141') {
1416                 decomposed.setCharAt(i, 'L');
1417             } else if (decomposed.charAt(i) == '\u0142') {
1418                 decomposed.setCharAt(i, 'l');
1419             }
1420         }
1421     }
1422 
1423     /**
1424      * Counts how many times the char appears in the given string.
1425      *
1426      * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1427      *
1428      * <pre>
1429      * StringUtils.countMatches(null, *)       = 0
1430      * StringUtils.countMatches("", *)         = 0
1431      * StringUtils.countMatches("abba", 0)  = 0
1432      * StringUtils.countMatches("abba", 'a')   = 2
1433      * StringUtils.countMatches("abba", 'b')  = 2
1434      * StringUtils.countMatches("abba", 'x') = 0
1435      * </pre>
1436      *
1437      * @param str  the CharSequence to check, may be null
1438      * @param ch  the char to count
1439      * @return the number of occurrences, 0 if the CharSequence is {@code null}
1440      * @since 3.4
1441      */
1442     public static int countMatches(final CharSequence str, final char ch) {
1443         if (isEmpty(str)) {
1444             return 0;
1445         }
1446         int count = 0;
1447         // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
1448         for (int i = 0; i < str.length(); i++) {
1449             if (ch == str.charAt(i)) {
1450                 count++;
1451             }
1452         }
1453         return count;
1454     }
1455 
1456     /**
1457      * Counts how many times the substring appears in the larger string.
1458      * Note that the code only counts non-overlapping matches.
1459      *
1460      * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
1461      *
1462      * <pre>
1463      * StringUtils.countMatches(null, *)       = 0
1464      * StringUtils.countMatches("", *)         = 0
1465      * StringUtils.countMatches("abba", null)  = 0
1466      * StringUtils.countMatches("abba", "")    = 0
1467      * StringUtils.countMatches("abba", "a")   = 2
1468      * StringUtils.countMatches("abba", "ab")  = 1
1469      * StringUtils.countMatches("abba", "xxx") = 0
1470      * StringUtils.countMatches("ababa", "aba") = 1
1471      * </pre>
1472      *
1473      * @param str  the CharSequence to check, may be null
1474      * @param sub  the substring to count, may be null
1475      * @return the number of occurrences, 0 if either CharSequence is {@code null}
1476      * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
1477      */
1478     public static int countMatches(final CharSequence str, final CharSequence sub) {
1479         if (isEmpty(str) || isEmpty(sub)) {
1480             return 0;
1481         }
1482         int count = 0;
1483         int idx = 0;
1484         while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
1485             count++;
1486             idx += sub.length();
1487         }
1488         return count;
1489     }
1490 
1491     /**
1492      * Returns either the passed in CharSequence, or if the CharSequence is
1493      * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.
1494      *
1495      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1496      *
1497      * <pre>
1498      * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
1499      * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
1500      * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
1501      * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
1502      * StringUtils.defaultIfBlank("", null)      = null
1503      * </pre>
1504      * @param <T> the specific kind of CharSequence
1505      * @param str the CharSequence to check, may be null
1506      * @param defaultStr  the default CharSequence to return
1507      *  if the input is whitespace, empty ("") or {@code null}, may be null
1508      * @return the passed in CharSequence, or the default
1509      * @see StringUtils#defaultString(String, String)
1510      */
1511     public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
1512         return isBlank(str) ? defaultStr : str;
1513     }
1514 
1515     /**
1516      * Returns either the passed in CharSequence, or if the CharSequence is
1517      * empty or {@code null}, the value of {@code defaultStr}.
1518      *
1519      * <pre>
1520      * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
1521      * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
1522      * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
1523      * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
1524      * StringUtils.defaultIfEmpty("", null)      = null
1525      * </pre>
1526      * @param <T> the specific kind of CharSequence
1527      * @param str  the CharSequence to check, may be null
1528      * @param defaultStr  the default CharSequence to return
1529      *  if the input is empty ("") or {@code null}, may be null
1530      * @return the passed in CharSequence, or the default
1531      * @see StringUtils#defaultString(String, String)
1532      */
1533     public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
1534         return isEmpty(str) ? defaultStr : str;
1535     }
1536 
1537     /**
1538      * Returns either the passed in String,
1539      * or if the String is {@code null}, an empty String ("").
1540      *
1541      * <pre>
1542      * StringUtils.defaultString(null)  = ""
1543      * StringUtils.defaultString("")    = ""
1544      * StringUtils.defaultString("bat") = "bat"
1545      * </pre>
1546      *
1547      * @see Objects#toString(Object, String)
1548      * @see String#valueOf(Object)
1549      * @param str  the String to check, may be null
1550      * @return the passed in String, or the empty String if it
1551      *  was {@code null}
1552      */
1553     public static String defaultString(final String str) {
1554         return Objects.toString(str, EMPTY);
1555     }
1556 
1557     /**
1558      * Returns either the given String, or if the String is
1559      * {@code null}, {@code nullDefault}.
1560      *
1561      * <pre>
1562      * StringUtils.defaultString(null, "NULL")  = "NULL"
1563      * StringUtils.defaultString("", "NULL")    = ""
1564      * StringUtils.defaultString("bat", "NULL") = "bat"
1565      * </pre>
1566      * <p>
1567      * Since this is now provided by Java, instead call {@link Objects#toString(Object, String)}:
1568      * </p>
1569      * <pre>
1570      * Objects.toString(null, "NULL")  = "NULL"
1571      * Objects.toString("", "NULL")    = ""
1572      * Objects.toString("bat", "NULL") = "bat"
1573      * </pre>
1574      *
1575      * @see Objects#toString(Object, String)
1576      * @see String#valueOf(Object)
1577      * @param str  the String to check, may be null
1578      * @param nullDefault  the default String to return
1579      *  if the input is {@code null}, may be null
1580      * @return the passed in String, or the default if it was {@code null}
1581      * @deprecated Use {@link Objects#toString(Object, String)}
1582      */
1583     @Deprecated
1584     public static String defaultString(final String str, final String nullDefault) {
1585         return Objects.toString(str, nullDefault);
1586     }
1587 
1588     /**
1589      * Deletes all whitespaces from a String as defined by
1590      * {@link Character#isWhitespace(char)}.
1591      *
1592      * <pre>
1593      * StringUtils.deleteWhitespace(null)         = null
1594      * StringUtils.deleteWhitespace("")           = ""
1595      * StringUtils.deleteWhitespace("abc")        = "abc"
1596      * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
1597      * </pre>
1598      *
1599      * @param str  the String to delete whitespace from, may be null
1600      * @return the String without whitespaces, {@code null} if null String input
1601      */
1602     public static String deleteWhitespace(final String str) {
1603         if (isEmpty(str)) {
1604             return str;
1605         }
1606         final int sz = str.length();
1607         final char[] chs = new char[sz];
1608         int count = 0;
1609         for (int i = 0; i < sz; i++) {
1610             if (!Character.isWhitespace(str.charAt(i))) {
1611                 chs[count++] = str.charAt(i);
1612             }
1613         }
1614         if (count == sz) {
1615             return str;
1616         }
1617         if (count == 0) {
1618             return EMPTY;
1619         }
1620         return new String(chs, 0, count);
1621     }
1622 
1623     /**
1624      * Compares two Strings, and returns the portion where they differ.
1625      * More precisely, return the remainder of the second String,
1626      * starting from where it's different from the first. This means that
1627      * the difference between "abc" and "ab" is the empty String and not "c".
1628      *
1629      * <p>For example,
1630      * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
1631      *
1632      * <pre>
1633      * StringUtils.difference(null, null) = null
1634      * StringUtils.difference("", "") = ""
1635      * StringUtils.difference("", "abc") = "abc"
1636      * StringUtils.difference("abc", "") = ""
1637      * StringUtils.difference("abc", "abc") = ""
1638      * StringUtils.difference("abc", "ab") = ""
1639      * StringUtils.difference("ab", "abxyz") = "xyz"
1640      * StringUtils.difference("abcde", "abxyz") = "xyz"
1641      * StringUtils.difference("abcde", "xyz") = "xyz"
1642      * </pre>
1643      *
1644      * @param str1  the first String, may be null
1645      * @param str2  the second String, may be null
1646      * @return the portion of str2 where it differs from str1; returns the
1647      * empty String if they are equal
1648      * @see #indexOfDifference(CharSequence,CharSequence)
1649      * @since 2.0
1650      */
1651     public static String difference(final String str1, final String str2) {
1652         if (str1 == null) {
1653             return str2;
1654         }
1655         if (str2 == null) {
1656             return str1;
1657         }
1658         final int at = indexOfDifference(str1, str2);
1659         if (at == INDEX_NOT_FOUND) {
1660             return EMPTY;
1661         }
1662         return str2.substring(at);
1663     }
1664 
1665     /**
1666      * Check if a CharSequence ends with a specified suffix.
1667      *
1668      * <p>{@code null}s are handled without exceptions. Two {@code null}
1669      * references are considered to be equal. The comparison is case-sensitive.</p>
1670      *
1671      * <pre>
1672      * StringUtils.endsWith(null, null)      = true
1673      * StringUtils.endsWith(null, "def")     = false
1674      * StringUtils.endsWith("abcdef", null)  = false
1675      * StringUtils.endsWith("abcdef", "def") = true
1676      * StringUtils.endsWith("ABCDEF", "def") = false
1677      * StringUtils.endsWith("ABCDEF", "cde") = false
1678      * StringUtils.endsWith("ABCDEF", "")    = true
1679      * </pre>
1680      *
1681      * @see String#endsWith(String)
1682      * @param str  the CharSequence to check, may be null
1683      * @param suffix the suffix to find, may be null
1684      * @return {@code true} if the CharSequence ends with the suffix, case-sensitive, or
1685      *  both {@code null}
1686      * @since 2.4
1687      * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
1688      */
1689     public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
1690         return endsWith(str, suffix, false);
1691     }
1692 
1693     /**
1694      * Check if a CharSequence ends with a specified suffix (optionally case insensitive).
1695      *
1696      * @see String#endsWith(String)
1697      * @param str  the CharSequence to check, may be null
1698      * @param suffix the suffix to find, may be null
1699      * @param ignoreCase indicates whether the compare should ignore case
1700      *  (case-insensitive) or not.
1701      * @return {@code true} if the CharSequence starts with the prefix or
1702      *  both {@code null}
1703      */
1704     private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
1705         if (str == null || suffix == null) {
1706             return str == suffix;
1707         }
1708         if (suffix.length() > str.length()) {
1709             return false;
1710         }
1711         final int strOffset = str.length() - suffix.length();
1712         return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
1713     }
1714 
1715     /**
1716      * Check if a CharSequence ends with any of the provided case-sensitive suffixes.
1717      *
1718      * <pre>
1719      * StringUtils.endsWithAny(null, null)      = false
1720      * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
1721      * StringUtils.endsWithAny("abcxyz", null)     = false
1722      * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
1723      * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
1724      * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
1725      * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
1726      * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
1727      * </pre>
1728      *
1729      * @param sequence  the CharSequence to check, may be null
1730      * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
1731      * @see StringUtils#endsWith(CharSequence, CharSequence)
1732      * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
1733      *   the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
1734      * @since 3.0
1735      */
1736     public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
1737         if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
1738             return false;
1739         }
1740         for (final CharSequence searchString : searchStrings) {
1741             if (endsWith(sequence, searchString)) {
1742                 return true;
1743             }
1744         }
1745         return false;
1746     }
1747 
1748     /**
1749      * Case insensitive check if a CharSequence ends with a specified suffix.
1750      *
1751      * <p>{@code null}s are handled without exceptions. Two {@code null}
1752      * references are considered to be equal. The comparison is case insensitive.</p>
1753      *
1754      * <pre>
1755      * StringUtils.endsWithIgnoreCase(null, null)      = true
1756      * StringUtils.endsWithIgnoreCase(null, "def")     = false
1757      * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
1758      * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
1759      * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
1760      * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
1761      * </pre>
1762      *
1763      * @see String#endsWith(String)
1764      * @param str  the CharSequence to check, may be null
1765      * @param suffix the suffix to find, may be null
1766      * @return {@code true} if the CharSequence ends with the suffix, case-insensitive, or
1767      *  both {@code null}
1768      * @since 2.4
1769      * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
1770      */
1771     public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
1772         return endsWith(str, suffix, true);
1773     }
1774 
1775     /**
1776      * Compares two CharSequences, returning {@code true} if they represent
1777      * equal sequences of characters.
1778      *
1779      * <p>{@code null}s are handled without exceptions. Two {@code null}
1780      * references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
1781      *
1782      * <pre>
1783      * StringUtils.equals(null, null)   = true
1784      * StringUtils.equals(null, "abc")  = false
1785      * StringUtils.equals("abc", null)  = false
1786      * StringUtils.equals("abc", "abc") = true
1787      * StringUtils.equals("abc", "ABC") = false
1788      * </pre>
1789      *
1790      * @param cs1  the first CharSequence, may be {@code null}
1791      * @param cs2  the second CharSequence, may be {@code null}
1792      * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
1793      * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
1794      * @see Object#equals(Object)
1795      * @see #equalsIgnoreCase(CharSequence, CharSequence)
1796      */
1797     public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
1798         if (cs1 == cs2) {
1799             return true;
1800         }
1801         if (cs1 == null || cs2 == null) {
1802             return false;
1803         }
1804         if (cs1.length() != cs2.length()) {
1805             return false;
1806         }
1807         if (cs1 instanceof String && cs2 instanceof String) {
1808             return cs1.equals(cs2);
1809         }
1810         // Step-wise comparison
1811         final int length = cs1.length();
1812         for (int i = 0; i < length; i++) {
1813             if (cs1.charAt(i) != cs2.charAt(i)) {
1814                 return false;
1815             }
1816         }
1817         return true;
1818     }
1819 
1820     /**
1821      * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1822      * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}.
1823      *
1824      * <pre>
1825      * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1826      * StringUtils.equalsAny(null, null, null)    = true
1827      * StringUtils.equalsAny(null, "abc", "def")  = false
1828      * StringUtils.equalsAny("abc", null, "def")  = false
1829      * StringUtils.equalsAny("abc", "abc", "def") = true
1830      * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1831      * </pre>
1832      *
1833      * @param string to compare, may be {@code null}.
1834      * @param searchStrings a vararg of strings, may be {@code null}.
1835      * @return {@code true} if the string is equal (case-sensitive) to any other element of {@code searchStrings};
1836      * {@code false} if {@code searchStrings} is null or contains no matches.
1837      * @since 3.5
1838      */
1839     public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1840         if (ArrayUtils.isNotEmpty(searchStrings)) {
1841             for (final CharSequence next : searchStrings) {
1842                 if (equals(string, next)) {
1843                     return true;
1844                 }
1845             }
1846         }
1847         return false;
1848     }
1849 
1850     /**
1851      * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
1852      * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
1853      *
1854      * <pre>
1855      * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1856      * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
1857      * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
1858      * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
1859      * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1860      * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1861      * </pre>
1862      *
1863      * @param string to compare, may be {@code null}.
1864      * @param searchStrings a vararg of strings, may be {@code null}.
1865      * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
1866      * {@code false} if {@code searchStrings} is null or contains no matches.
1867      * @since 3.5
1868      */
1869     public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) {
1870         if (ArrayUtils.isNotEmpty(searchStrings)) {
1871             for (final CharSequence next : searchStrings) {
1872                 if (equalsIgnoreCase(string, next)) {
1873                     return true;
1874                 }
1875             }
1876         }
1877         return false;
1878     }
1879 
1880     /**
1881      * Compares two CharSequences, returning {@code true} if they represent
1882      * equal sequences of characters, ignoring case.
1883      *
1884      * <p>{@code null}s are handled without exceptions. Two {@code null}
1885      * references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
1886      *
1887      * <pre>
1888      * StringUtils.equalsIgnoreCase(null, null)   = true
1889      * StringUtils.equalsIgnoreCase(null, "abc")  = false
1890      * StringUtils.equalsIgnoreCase("abc", null)  = false
1891      * StringUtils.equalsIgnoreCase("abc", "abc") = true
1892      * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1893      * </pre>
1894      *
1895      * @param cs1  the first CharSequence, may be {@code null}
1896      * @param cs2  the second CharSequence, may be {@code null}
1897      * @return {@code true} if the CharSequences are equal (case-insensitive), or both {@code null}
1898      * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1899      * @see #equals(CharSequence, CharSequence)
1900      */
1901     public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
1902         if (cs1 == cs2) {
1903             return true;
1904         }
1905         if (cs1 == null || cs2 == null) {
1906             return false;
1907         }
1908         if (cs1.length() != cs2.length()) {
1909             return false;
1910         }
1911         return CharSequenceUtils.regionMatches(cs1, true, 0, cs2, 0, cs1.length());
1912     }
1913 
1914     /**
1915      * Returns the first value in the array which is not empty (""),
1916      * {@code null} or whitespace only.
1917      *
1918      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
1919      *
1920      * <p>If all values are blank or the array is {@code null}
1921      * or empty then {@code null} is returned.</p>
1922      *
1923      * <pre>
1924      * StringUtils.firstNonBlank(null, null, null)     = null
1925      * StringUtils.firstNonBlank(null, "", " ")        = null
1926      * StringUtils.firstNonBlank("abc")                = "abc"
1927      * StringUtils.firstNonBlank(null, "xyz")          = "xyz"
1928      * StringUtils.firstNonBlank(null, "", " ", "xyz") = "xyz"
1929      * StringUtils.firstNonBlank(null, "xyz", "abc")   = "xyz"
1930      * StringUtils.firstNonBlank()                     = null
1931      * </pre>
1932      *
1933      * @param <T> the specific kind of CharSequence
1934      * @param values  the values to test, may be {@code null} or empty
1935      * @return the first value from {@code values} which is not blank,
1936      *  or {@code null} if there are no non-blank values
1937      * @since 3.8
1938      */
1939     @SafeVarargs
1940     public static <T extends CharSequence> T firstNonBlank(final T... values) {
1941         if (values != null) {
1942             for (final T val : values) {
1943                 if (isNotBlank(val)) {
1944                     return val;
1945                 }
1946             }
1947         }
1948         return null;
1949     }
1950 
1951     /**
1952      * Returns the first value in the array which is not empty.
1953      *
1954      * <p>If all values are empty or the array is {@code null}
1955      * or empty then {@code null} is returned.</p>
1956      *
1957      * <pre>
1958      * StringUtils.firstNonEmpty(null, null, null)   = null
1959      * StringUtils.firstNonEmpty(null, null, "")     = null
1960      * StringUtils.firstNonEmpty(null, "", " ")      = " "
1961      * StringUtils.firstNonEmpty("abc")              = "abc"
1962      * StringUtils.firstNonEmpty(null, "xyz")        = "xyz"
1963      * StringUtils.firstNonEmpty("", "xyz")          = "xyz"
1964      * StringUtils.firstNonEmpty(null, "xyz", "abc") = "xyz"
1965      * StringUtils.firstNonEmpty()                   = null
1966      * </pre>
1967      *
1968      * @param <T> the specific kind of CharSequence
1969      * @param values  the values to test, may be {@code null} or empty
1970      * @return the first value from {@code values} which is not empty,
1971      *  or {@code null} if there are no non-empty values
1972      * @since 3.8
1973      */
1974     @SafeVarargs
1975     public static <T extends CharSequence> T firstNonEmpty(final T... values) {
1976         if (values != null) {
1977             for (final T val : values) {
1978                 if (isNotEmpty(val)) {
1979                     return val;
1980                 }
1981             }
1982         }
1983         return null;
1984     }
1985 
1986     /**
1987      * Calls {@link String#getBytes(Charset)} in a null-safe manner.
1988      *
1989      * @param string input string
1990      * @param charset The {@link Charset} to encode the {@link String}. If null, then use the default Charset.
1991      * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(Charset)} otherwise.
1992      * @see String#getBytes(Charset)
1993      * @since 3.10
1994      */
1995     public static byte[] getBytes(final String string, final Charset charset) {
1996         return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharset(charset));
1997     }
1998 
1999     /**
2000      * Calls {@link String#getBytes(String)} in a null-safe manner.
2001      *
2002      * @param string input string
2003      * @param charset The {@link Charset} name to encode the {@link String}. If null, then use the default Charset.
2004      * @return The empty byte[] if {@code string} is null, the result of {@link String#getBytes(String)} otherwise.
2005      * @throws UnsupportedEncodingException Thrown when the named charset is not supported.
2006      * @see String#getBytes(String)
2007      * @since 3.10
2008      */
2009     public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException {
2010         return string == null ? ArrayUtils.EMPTY_BYTE_ARRAY : string.getBytes(Charsets.toCharsetName(charset));
2011     }
2012 
2013     /**
2014      * Compares all Strings in an array and returns the initial sequence of
2015      * characters that is common to all of them.
2016      *
2017      * <p>For example,
2018      * {@code getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "}</p>
2019      *
2020      * <pre>
2021      * StringUtils.getCommonPrefix(null) = ""
2022      * StringUtils.getCommonPrefix(new String[] {}) = ""
2023      * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
2024      * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
2025      * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
2026      * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
2027      * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
2028      * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
2029      * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
2030      * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
2031      * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
2032      * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
2033      * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
2034      * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
2035      * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
2036      * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
2037      * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
2038      * </pre>
2039      *
2040      * @param strs  array of String objects, entries may be null
2041      * @return the initial sequence of characters that are common to all Strings
2042      * in the array; empty String if the array is null, the elements are all null
2043      * or if there is no common prefix.
2044      * @since 2.4
2045      */
2046     public static String getCommonPrefix(final String... strs) {
2047         if (ArrayUtils.isEmpty(strs)) {
2048             return EMPTY;
2049         }
2050         final int smallestIndexOfDiff = indexOfDifference(strs);
2051         if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
2052             // all strings were identical
2053             if (strs[0] == null) {
2054                 return EMPTY;
2055             }
2056             return strs[0];
2057         }
2058         if (smallestIndexOfDiff == 0) {
2059             // there were no common initial characters
2060             return EMPTY;
2061         }
2062         // we found a common initial character sequence
2063         return strs[0].substring(0, smallestIndexOfDiff);
2064     }
2065 
2066     /**
2067      * Checks if a String {@code str} contains Unicode digits,
2068      * if yes then concatenate all the digits in {@code str} and return it as a String.
2069      *
2070      * <p>An empty ("") String will be returned if no digits found in {@code str}.</p>
2071      *
2072      * <pre>
2073      * StringUtils.getDigits(null)  = null
2074      * StringUtils.getDigits("")    = ""
2075      * StringUtils.getDigits("abc") = ""
2076      * StringUtils.getDigits("1000$") = "1000"
2077      * StringUtils.getDigits("1123~45") = "112345"
2078      * StringUtils.getDigits("(541) 754-3010") = "5417543010"
2079      * StringUtils.getDigits("\u0967\u0968\u0969") = "\u0967\u0968\u0969"
2080      * </pre>
2081      *
2082      * @param str the String to extract digits from, may be null
2083      * @return String with only digits,
2084      *           or an empty ("") String if no digits found,
2085      *           or {@code null} String if {@code str} is null
2086      * @since 3.6
2087      */
2088     public static String getDigits(final String str) {
2089         if (isEmpty(str)) {
2090             return str;
2091         }
2092         final int sz = str.length();
2093         final StringBuilder strDigits = new StringBuilder(sz);
2094         for (int i = 0; i < sz; i++) {
2095             final char tempChar = str.charAt(i);
2096             if (Character.isDigit(tempChar)) {
2097                 strDigits.append(tempChar);
2098             }
2099         }
2100         return strDigits.toString();
2101     }
2102 
2103     /**
2104      * Find the Fuzzy Distance which indicates the similarity score between two Strings.
2105      *
2106      * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
2107      * TextMate, Atom and others. One point is given for every matched character. Subsequent
2108      * matches yield two bonus points. A higher score indicates a higher similarity.</p>
2109      *
2110      * <pre>
2111      * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
2112      * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
2113      * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
2114      * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
2115      * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
2116      * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
2117      * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
2118      * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
2119      * </pre>
2120      *
2121      * @param term a full term that should be matched against, must not be null
2122      * @param query the query that will be matched against a term, must not be null
2123      * @param locale This string matching logic is case-insensitive. A locale is necessary to normalize
2124      *  both Strings to lower case.
2125      * @return result score
2126      * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
2127      * @since 3.4
2128      * @deprecated As of 3.6, use Apache Commons Text
2129      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
2130      * FuzzyScore</a> instead
2131      */
2132     @Deprecated
2133     public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
2134         if (term == null || query == null) {
2135             throw new IllegalArgumentException("Strings must not be null");
2136         }
2137         if (locale == null) {
2138             throw new IllegalArgumentException("Locale must not be null");
2139         }
2140 
2141         // fuzzy logic is case-insensitive. We normalize the Strings to lower
2142         // case right from the start. Turning characters to lower case
2143         // via Character.toLowerCase(char) is unfortunately insufficient
2144         // as it does not accept a locale.
2145         final String termLowerCase = term.toString().toLowerCase(locale);
2146         final String queryLowerCase = query.toString().toLowerCase(locale);
2147 
2148         // the resulting score
2149         int score = 0;
2150 
2151         // the position in the term which will be scanned next for potential
2152         // query character matches
2153         int termIndex = 0;
2154 
2155         // index of the previously matched character in the term
2156         int previousMatchingCharacterIndex = Integer.MIN_VALUE;
2157 
2158         for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
2159             final char queryChar = queryLowerCase.charAt(queryIndex);
2160 
2161             boolean termCharacterMatchFound = false;
2162             for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
2163                 final char termChar = termLowerCase.charAt(termIndex);
2164 
2165                 if (queryChar == termChar) {
2166                     // simple character matches result in one point
2167                     score++;
2168 
2169                     // subsequent character matches further improve
2170                     // the score.
2171                     if (previousMatchingCharacterIndex + 1 == termIndex) {
2172                         score += 2;
2173                     }
2174 
2175                     previousMatchingCharacterIndex = termIndex;
2176 
2177                     // we can leave the nested loop. Every character in the
2178                     // query can match at most one character in the term.
2179                     termCharacterMatchFound = true;
2180                 }
2181             }
2182         }
2183 
2184         return score;
2185     }
2186 
2187     /**
2188      * Returns either the passed in CharSequence, or if the CharSequence is
2189      * whitespace, empty ("") or {@code null}, the value supplied by {@code defaultStrSupplier}.
2190      *
2191      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2192      *
2193      * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2194      *
2195      * <pre>
2196      * {@code
2197      * StringUtils.getIfBlank(null, () -> "NULL")   = "NULL"
2198      * StringUtils.getIfBlank("", () -> "NULL")     = "NULL"
2199      * StringUtils.getIfBlank(" ", () -> "NULL")    = "NULL"
2200      * StringUtils.getIfBlank("bat", () -> "NULL")  = "bat"
2201      * StringUtils.getIfBlank("", () -> null)       = null
2202      * StringUtils.getIfBlank("", null)             = null
2203      * }</pre>
2204      * @param <T> the specific kind of CharSequence
2205      * @param str the CharSequence to check, may be null
2206      * @param defaultSupplier the supplier of default CharSequence to return
2207      *  if the input is whitespace, empty ("") or {@code null}, may be null
2208      * @return the passed in CharSequence, or the default
2209      * @see StringUtils#defaultString(String, String)
2210      * @since 3.10
2211      */
2212     public static <T extends CharSequence> T getIfBlank(final T str, final Supplier<T> defaultSupplier) {
2213         return isBlank(str) ? Suppliers.get(defaultSupplier) : str;
2214     }
2215 
2216     /**
2217      * Returns either the passed in CharSequence, or if the CharSequence is
2218      * empty or {@code null}, the value supplied by {@code defaultStrSupplier}.
2219      *
2220      * <p>Caller responsible for thread-safety and exception handling of default value supplier</p>
2221      *
2222      * <pre>
2223      * {@code
2224      * StringUtils.getIfEmpty(null, () -> "NULL")    = "NULL"
2225      * StringUtils.getIfEmpty("", () -> "NULL")      = "NULL"
2226      * StringUtils.getIfEmpty(" ", () -> "NULL")     = " "
2227      * StringUtils.getIfEmpty("bat", () -> "NULL")   = "bat"
2228      * StringUtils.getIfEmpty("", () -> null)        = null
2229      * StringUtils.getIfEmpty("", null)              = null
2230      * }
2231      * </pre>
2232      * @param <T> the specific kind of CharSequence
2233      * @param str  the CharSequence to check, may be null
2234      * @param defaultSupplier  the supplier of default CharSequence to return
2235      *  if the input is empty ("") or {@code null}, may be null
2236      * @return the passed in CharSequence, or the default
2237      * @see StringUtils#defaultString(String, String)
2238      * @since 3.10
2239      */
2240     public static <T extends CharSequence> T getIfEmpty(final T str, final Supplier<T> defaultSupplier) {
2241         return isEmpty(str) ? Suppliers.get(defaultSupplier) : str;
2242     }
2243 
2244     /**
2245      * Find the Jaro Winkler Distance which indicates the similarity score between two Strings.
2246      *
2247      * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
2248      * Winkler increased this measure for matching initial characters.</p>
2249      *
2250      * <p>This implementation is based on the Jaro Winkler similarity algorithm
2251      * 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>
2252      *
2253      * <pre>
2254      * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
2255      * StringUtils.getJaroWinklerDistance("", "")              = 0.0
2256      * StringUtils.getJaroWinklerDistance("", "a")             = 0.0
2257      * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
2258      * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
2259      * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
2260      * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
2261      * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
2262      * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
2263      * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
2264      * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
2265      * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
2266      * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
2267      * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
2268      * </pre>
2269      *
2270      * @param first the first String, must not be null
2271      * @param second the second String, must not be null
2272      * @return result distance
2273      * @throws IllegalArgumentException if either String input {@code null}
2274      * @since 3.3
2275      * @deprecated As of 3.6, use Apache Commons Text
2276      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
2277      * JaroWinklerDistance</a> instead
2278      */
2279     @Deprecated
2280     public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
2281         final double DEFAULT_SCALING_FACTOR = 0.1;
2282 
2283         if (first == null || second == null) {
2284             throw new IllegalArgumentException("Strings must not be null");
2285         }
2286 
2287         final int[] mtp = matches(first, second);
2288         final double m = mtp[0];
2289         if (m == 0) {
2290             return 0D;
2291         }
2292         final double j = (m / first.length() + m / second.length() + (m - mtp[1]) / m) / 3;
2293         final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
2294         return Math.round(jw * 100.0D) / 100.0D;
2295     }
2296 
2297     /**
2298      * Find the Levenshtein distance between two Strings.
2299      *
2300      * <p>This is the number of changes needed to change one String into
2301      * another, where each change is a single character modification (deletion,
2302      * insertion or substitution).</p>
2303      *
2304      * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
2305      * <a href="https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
2306      * https://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
2307      *
2308      * <pre>
2309      * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
2310      * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
2311      * StringUtils.getLevenshteinDistance("", "")              = 0
2312      * StringUtils.getLevenshteinDistance("", "a")             = 1
2313      * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
2314      * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
2315      * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
2316      * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
2317      * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
2318      * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
2319      * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
2320      * </pre>
2321      *
2322      * @param s  the first String, must not be null
2323      * @param t  the second String, must not be null
2324      * @return result distance
2325      * @throws IllegalArgumentException if either String input {@code null}
2326      * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
2327      * getLevenshteinDistance(CharSequence, CharSequence)
2328      * @deprecated As of 3.6, use Apache Commons Text
2329      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2330      * LevenshteinDistance</a> instead
2331      */
2332     @Deprecated
2333     public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
2334         if (s == null || t == null) {
2335             throw new IllegalArgumentException("Strings must not be null");
2336         }
2337 
2338         int n = s.length();
2339         int m = t.length();
2340 
2341         if (n == 0) {
2342             return m;
2343         }
2344         if (m == 0) {
2345             return n;
2346         }
2347 
2348         if (n > m) {
2349             // swap the input strings to consume less memory
2350             final CharSequence tmp = s;
2351             s = t;
2352             t = tmp;
2353             n = m;
2354             m = t.length();
2355         }
2356 
2357         final int[] p = new int[n + 1];
2358         // indexes into strings s and t
2359         int i; // iterates through s
2360         int j; // iterates through t
2361         int upperleft;
2362         int upper;
2363 
2364         char jOfT; // jth character of t
2365         int cost;
2366 
2367         for (i = 0; i <= n; i++) {
2368             p[i] = i;
2369         }
2370 
2371         for (j = 1; j <= m; j++) {
2372             upperleft = p[0];
2373             jOfT = t.charAt(j - 1);
2374             p[0] = j;
2375 
2376             for (i = 1; i <= n; i++) {
2377                 upper = p[i];
2378                 cost = s.charAt(i - 1) == jOfT ? 0 : 1;
2379                 // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
2380                 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
2381                 upperleft = upper;
2382             }
2383         }
2384 
2385         return p[n];
2386     }
2387 
2388     /**
2389      * Find the Levenshtein distance between two Strings if it's less than or equal to a given
2390      * threshold.
2391      *
2392      * <p>This is the number of changes needed to change one String into
2393      * another, where each change is a single character modification (deletion,
2394      * insertion or substitution).</p>
2395      *
2396      * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
2397      * and Chas Emerick's implementation of the Levenshtein distance algorithm from
2398      * <a href="https://web.archive.org/web/20120212021906/http%3A//www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
2399      *
2400      * <pre>
2401      * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
2402      * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
2403      * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
2404      * StringUtils.getLevenshteinDistance("", "", 0)              = 0
2405      * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
2406      * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
2407      * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
2408      * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
2409      * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
2410      * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
2411      * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
2412      * </pre>
2413      *
2414      * @param s  the first String, must not be null
2415      * @param t  the second String, must not be null
2416      * @param threshold the target threshold, must not be negative
2417      * @return result distance, or {@code -1} if the distance would be greater than the threshold
2418      * @throws IllegalArgumentException if either String input {@code null} or negative threshold
2419      * @deprecated As of 3.6, use Apache Commons Text
2420      * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
2421      * LevenshteinDistance</a> instead
2422      */
2423     @Deprecated
2424     public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
2425         if (s == null || t == null) {
2426             throw new IllegalArgumentException("Strings must not be null");
2427         }
2428         if (threshold < 0) {
2429             throw new IllegalArgumentException("Threshold must not be negative");
2430         }
2431 
2432         /*
2433         This implementation only computes the distance if it's less than or equal to the
2434         threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
2435         distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
2436         computing a diagonal stripe of width 2k + 1 of the cost table.
2437         It is also possible to use this to compute the unbounded Levenshtein distance by starting
2438         the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
2439         d is the distance.
2440 
2441         One subtlety comes from needing to ignore entries on the border of our stripe
2442         eg.
2443         p[] = |#|#|#|*
2444         d[] =  *|#|#|#|
2445         We must ignore the entry to the left of the leftmost member
2446         We must ignore the entry above the rightmost member
2447 
2448         Another subtlety comes from our stripe running off the matrix if the strings aren't
2449         of the same size.  Since string s is always swapped to be the shorter of the two,
2450         the stripe will always run off to the upper right instead of the lower left of the matrix.
2451 
2452         As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
2453         In this case we're going to walk a stripe of length 3.  The matrix would look like so:
2454 
2455            1 2 3 4 5
2456         1 |#|#| | | |
2457         2 |#|#|#| | |
2458         3 | |#|#|#| |
2459         4 | | |#|#|#|
2460         5 | | | |#|#|
2461         6 | | | | |#|
2462         7 | | | | | |
2463 
2464         Note how the stripe leads off the table as there is no possible way to turn a string of length 5
2465         into one of length 7 in edit distance of 1.
2466 
2467         Additionally, this implementation decreases memory usage by using two
2468         single-dimensional arrays and swapping them back and forth instead of allocating
2469         an entire n by m matrix.  This requires a few minor changes, such as immediately returning
2470         when it's detected that the stripe has run off the matrix and initially filling the arrays with
2471         large values so that entries we don't compute are ignored.
2472 
2473         See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
2474          */
2475 
2476         int n = s.length(); // length of s
2477         int m = t.length(); // length of t
2478 
2479         // if one string is empty, the edit distance is necessarily the length of the other
2480         if (n == 0) {
2481             return m <= threshold ? m : -1;
2482         }
2483         if (m == 0) {
2484             return n <= threshold ? n : -1;
2485         }
2486         if (Math.abs(n - m) > threshold) {
2487             // no need to calculate the distance if the length difference is greater than the threshold
2488             return -1;
2489         }
2490 
2491         if (n > m) {
2492             // swap the two strings to consume less memory
2493             final CharSequence tmp = s;
2494             s = t;
2495             t = tmp;
2496             n = m;
2497             m = t.length();
2498         }
2499 
2500         int[] p = new int[n + 1]; // 'previous' cost array, horizontally
2501         int[] d = new int[n + 1]; // cost array, horizontally
2502         int[] tmp; // placeholder to assist in swapping p and d
2503 
2504         // fill in starting table values
2505         final int boundary = Math.min(n, threshold) + 1;
2506         for (int i = 0; i < boundary; i++) {
2507             p[i] = i;
2508         }
2509         // these fills ensure that the value above the rightmost entry of our
2510         // stripe will be ignored in following loop iterations
2511         Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
2512         Arrays.fill(d, Integer.MAX_VALUE);
2513 
2514         // iterates through t
2515         for (int j = 1; j <= m; j++) {
2516             final char jOfT = t.charAt(j - 1); // jth character of t
2517             d[0] = j;
2518 
2519             // compute stripe indices, constrain to array size
2520             final int min = Math.max(1, j - threshold);
2521             final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
2522 
2523             // the stripe may lead off of the table if s and t are of different sizes
2524             if (min > max) {
2525                 return -1;
2526             }
2527 
2528             // ignore entry left of leftmost
2529             if (min > 1) {
2530                 d[min - 1] = Integer.MAX_VALUE;
2531             }
2532 
2533             // iterates through [min, max] in s
2534             for (int i = min; i <= max; i++) {
2535                 if (s.charAt(i - 1) == jOfT) {
2536                     // diagonally left and up
2537                     d[i] = p[i - 1];
2538                 } else {
2539                     // 1 + minimum of cell to the left, to the top, diagonally left and up
2540                     d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
2541                 }
2542             }
2543 
2544             // copy current distance counts to 'previous row' distance counts
2545             tmp = p;
2546             p = d;
2547             d = tmp;
2548         }
2549 
2550         // if p[n] is greater than the threshold, there's no guarantee on it being the correct
2551         // distance
2552         if (p[n] <= threshold) {
2553             return p[n];
2554         }
2555         return -1;
2556     }
2557 
2558     /**
2559      * Finds the first index within a CharSequence, handling {@code null}.
2560      * This method uses {@link String#indexOf(String, int)} if possible.
2561      *
2562      * <p>A {@code null} CharSequence will return {@code -1}.</p>
2563      *
2564      * <pre>
2565      * StringUtils.indexOf(null, *)          = -1
2566      * StringUtils.indexOf(*, null)          = -1
2567      * StringUtils.indexOf("", "")           = 0
2568      * StringUtils.indexOf("", *)            = -1 (except when * = "")
2569      * StringUtils.indexOf("aabaabaa", "a")  = 0
2570      * StringUtils.indexOf("aabaabaa", "b")  = 2
2571      * StringUtils.indexOf("aabaabaa", "ab") = 1
2572      * StringUtils.indexOf("aabaabaa", "")   = 0
2573      * </pre>
2574      *
2575      * @param seq  the CharSequence to check, may be null
2576      * @param searchSeq  the CharSequence to find, may be null
2577      * @return the first index of the search CharSequence,
2578      *  -1 if no match or {@code null} string input
2579      * @since 2.0
2580      * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
2581      */
2582     public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
2583         if (seq == null || searchSeq == null) {
2584             return INDEX_NOT_FOUND;
2585         }
2586         return CharSequenceUtils.indexOf(seq, searchSeq, 0);
2587     }
2588 
2589     /**
2590      * Finds the first index within a CharSequence, handling {@code null}.
2591      * This method uses {@link String#indexOf(String, int)} if possible.
2592      *
2593      * <p>A {@code null} CharSequence will return {@code -1}.
2594      * A negative start position is treated as zero.
2595      * An empty ("") search CharSequence always matches.
2596      * A start position greater than the string length only matches
2597      * an empty search CharSequence.</p>
2598      *
2599      * <pre>
2600      * StringUtils.indexOf(null, *, *)          = -1
2601      * StringUtils.indexOf(*, null, *)          = -1
2602      * StringUtils.indexOf("", "", 0)           = 0
2603      * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
2604      * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
2605      * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
2606      * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
2607      * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
2608      * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
2609      * StringUtils.indexOf("aabaabaa", "b", -1) = 2
2610      * StringUtils.indexOf("aabaabaa", "", 2)   = 2
2611      * StringUtils.indexOf("abc", "", 9)        = 3
2612      * </pre>
2613      *
2614      * @param seq  the CharSequence to check, may be null
2615      * @param searchSeq  the CharSequence to find, may be null
2616      * @param startPos  the start position, negative treated as zero
2617      * @return the first index of the search CharSequence (always &ge; startPos),
2618      *  -1 if no match or {@code null} string input
2619      * @since 2.0
2620      * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
2621      */
2622     public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
2623         if (seq == null || searchSeq == null) {
2624             return INDEX_NOT_FOUND;
2625         }
2626         return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
2627     }
2628 
2629     /**
2630      * Returns the index within {@code seq} of the first occurrence of
2631      * the specified character. If a character with value
2632      * {@code searchChar} occurs in the character sequence represented by
2633      * {@code seq} {@link CharSequence} object, then the index (in Unicode
2634      * code units) of the first such occurrence is returned. For
2635      * values of {@code searchChar} in the range from 0 to 0xFFFF
2636      * (inclusive), this is the smallest value <i>k</i> such that:
2637      * <blockquote><pre>
2638      * this.charAt(<i>k</i>) == searchChar
2639      * </pre></blockquote>
2640      * is true. For other values of {@code searchChar}, it is the
2641      * smallest value <i>k</i> such that:
2642      * <blockquote><pre>
2643      * this.codePointAt(<i>k</i>) == searchChar
2644      * </pre></blockquote>
2645      * is true. In either case, if no such character occurs in {@code seq},
2646      * then {@code INDEX_NOT_FOUND (-1)} is returned.
2647      *
2648      * <p>Furthermore, a {@code null} or empty ("") CharSequence will
2649      * return {@code INDEX_NOT_FOUND (-1)}.</p>
2650      *
2651      * <pre>
2652      * StringUtils.indexOf(null, *)         = -1
2653      * StringUtils.indexOf("", *)           = -1
2654      * StringUtils.indexOf("aabaabaa", 'a') = 0
2655      * StringUtils.indexOf("aabaabaa", 'b') = 2
2656      * </pre>
2657      *
2658      * @param seq  the CharSequence to check, may be null
2659      * @param searchChar  the character to find
2660      * @return the first index of the search character,
2661      *  -1 if no match or {@code null} string input
2662      * @since 2.0
2663      * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
2664      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2665      */
2666     public static int indexOf(final CharSequence seq, final int searchChar) {
2667         if (isEmpty(seq)) {
2668             return INDEX_NOT_FOUND;
2669         }
2670         return CharSequenceUtils.indexOf(seq, searchChar, 0);
2671     }
2672 
2673     /**
2674      * Returns the index within {@code seq} of the first occurrence of the
2675      * specified character, starting the search at the specified index.
2676      * <p>
2677      * If a character with value {@code searchChar} occurs in the
2678      * character sequence represented by the {@code seq} {@link CharSequence}
2679      * object at an index no smaller than {@code startPos}, then
2680      * the index of the first such occurrence is returned. For values
2681      * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
2682      * this is the smallest value <i>k</i> such that:
2683      * <blockquote><pre>
2684      * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
2685      * </pre></blockquote>
2686      * is true. For other values of {@code searchChar}, it is the
2687      * smallest value <i>k</i> such that:
2688      * <blockquote><pre>
2689      * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
2690      * </pre></blockquote>
2691      * is true. In either case, if no such character occurs in {@code seq}
2692      * at or after position {@code startPos}, then
2693      * {@code -1} is returned.
2694      *
2695      * <p>
2696      * There is no restriction on the value of {@code startPos}. If it
2697      * is negative, it has the same effect as if it were zero: this entire
2698      * string may be searched. If it is greater than the length of this
2699      * string, it has the same effect as if it were equal to the length of
2700      * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
2701      * {@code null} or empty ("") CharSequence will
2702      * return {@code (INDEX_NOT_FOUND) -1}.
2703      *
2704      * <p>All indices are specified in {@code char} values
2705      * (Unicode code units).
2706      *
2707      * <pre>
2708      * StringUtils.indexOf(null, *, *)          = -1
2709      * StringUtils.indexOf("", *, *)            = -1
2710      * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
2711      * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
2712      * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
2713      * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
2714      * </pre>
2715      *
2716      * @param seq  the CharSequence to check, may be null
2717      * @param searchChar  the character to find
2718      * @param startPos  the start position, negative treated as zero
2719      * @return the first index of the search character (always &ge; startPos),
2720      *  -1 if no match or {@code null} string input
2721      * @since 2.0
2722      * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
2723      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
2724      */
2725     public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
2726         if (isEmpty(seq)) {
2727             return INDEX_NOT_FOUND;
2728         }
2729         return CharSequenceUtils.indexOf(seq, searchChar, startPos);
2730     }
2731 
2732     /**
2733      * Search a CharSequence to find the first index of any
2734      * character in the given set of characters.
2735      *
2736      * <p>A {@code null} String will return {@code -1}.
2737      * A {@code null} or zero length search array will return {@code -1}.</p>
2738      *
2739      * <pre>
2740      * StringUtils.indexOfAny(null, *)                  = -1
2741      * StringUtils.indexOfAny("", *)                    = -1
2742      * StringUtils.indexOfAny(*, null)                  = -1
2743      * StringUtils.indexOfAny(*, [])                    = -1
2744      * StringUtils.indexOfAny("zzabyycdxx", ['z', 'a']) = 0
2745      * StringUtils.indexOfAny("zzabyycdxx", ['b', 'y']) = 3
2746      * StringUtils.indexOfAny("aba", ['z'])             = -1
2747      * </pre>
2748      *
2749      * @param cs  the CharSequence to check, may be null
2750      * @param searchChars  the chars to search for, may be null
2751      * @return the index of any of the chars, -1 if no match or null input
2752      * @since 2.0
2753      * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2754      */
2755     public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2756         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2757             return INDEX_NOT_FOUND;
2758         }
2759         final int csLen = cs.length();
2760         final int csLast = csLen - 1;
2761         final int searchLen = searchChars.length;
2762         final int searchLast = searchLen - 1;
2763         for (int i = 0; i < csLen; i++) {
2764             final char ch = cs.charAt(i);
2765             for (int j = 0; j < searchLen; j++) {
2766                 if (searchChars[j] == ch) {
2767                     if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
2768                         return i;
2769                     }
2770                     // ch is a supplementary character
2771                     if (searchChars[j + 1] == cs.charAt(i + 1)) {
2772                         return i;
2773                     }
2774                 }
2775             }
2776         }
2777         return INDEX_NOT_FOUND;
2778     }
2779 
2780     /**
2781      * Find the first index of any of a set of potential substrings.
2782      *
2783      * <p>A {@code null} CharSequence will return {@code -1}.
2784      * A {@code null} or zero length search array will return {@code -1}.
2785      * A {@code null} search array entry will be ignored, but a search
2786      * array containing "" will return {@code 0} if {@code str} is not
2787      * null. This method uses {@link String#indexOf(String)} if possible.</p>
2788      *
2789      * <pre>
2790      * StringUtils.indexOfAny(null, *)                      = -1
2791      * StringUtils.indexOfAny(*, null)                      = -1
2792      * StringUtils.indexOfAny(*, [])                        = -1
2793      * StringUtils.indexOfAny("zzabyycdxx", ["ab", "cd"])   = 2
2794      * StringUtils.indexOfAny("zzabyycdxx", ["cd", "ab"])   = 2
2795      * StringUtils.indexOfAny("zzabyycdxx", ["mn", "op"])   = -1
2796      * StringUtils.indexOfAny("zzabyycdxx", ["zab", "aby"]) = 1
2797      * StringUtils.indexOfAny("zzabyycdxx", [""])           = 0
2798      * StringUtils.indexOfAny("", [""])                     = 0
2799      * StringUtils.indexOfAny("", ["a"])                    = -1
2800      * </pre>
2801      *
2802      * @param str  the CharSequence to check, may be null
2803      * @param searchStrs  the CharSequences to search for, may be null
2804      * @return the first index of any of the searchStrs in str, -1 if no match
2805      * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2806      */
2807     public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2808         if (str == null || searchStrs == null) {
2809             return INDEX_NOT_FOUND;
2810         }
2811 
2812         // String's can't have a MAX_VALUEth index.
2813         int ret = Integer.MAX_VALUE;
2814 
2815         int tmp;
2816         for (final CharSequence search : searchStrs) {
2817             if (search == null) {
2818                 continue;
2819             }
2820             tmp = CharSequenceUtils.indexOf(str, search, 0);
2821             if (tmp == INDEX_NOT_FOUND) {
2822                 continue;
2823             }
2824 
2825             if (tmp < ret) {
2826                 ret = tmp;
2827             }
2828         }
2829 
2830         return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2831     }
2832 
2833     /**
2834      * Search a CharSequence to find the first index of any
2835      * character in the given set of characters.
2836      *
2837      * <p>A {@code null} String will return {@code -1}.
2838      * A {@code null} search string will return {@code -1}.</p>
2839      *
2840      * <pre>
2841      * StringUtils.indexOfAny(null, *)            = -1
2842      * StringUtils.indexOfAny("", *)              = -1
2843      * StringUtils.indexOfAny(*, null)            = -1
2844      * StringUtils.indexOfAny(*, "")              = -1
2845      * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2846      * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2847      * StringUtils.indexOfAny("aba", "z")         = -1
2848      * </pre>
2849      *
2850      * @param cs  the CharSequence to check, may be null
2851      * @param searchChars  the chars to search for, may be null
2852      * @return the index of any of the chars, -1 if no match or null input
2853      * @since 2.0
2854      * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2855      */
2856     public static int indexOfAny(final CharSequence cs, final String searchChars) {
2857         if (isEmpty(cs) || isEmpty(searchChars)) {
2858             return INDEX_NOT_FOUND;
2859         }
2860         return indexOfAny(cs, searchChars.toCharArray());
2861     }
2862 
2863     /**
2864      * Searches a CharSequence to find the first index of any
2865      * character not in the given set of characters.
2866      *
2867      * <p>A {@code null} CharSequence will return {@code -1}.
2868      * A {@code null} or zero length search array will return {@code -1}.</p>
2869      *
2870      * <pre>
2871      * StringUtils.indexOfAnyBut(null, *)                              = -1
2872      * StringUtils.indexOfAnyBut("", *)                                = -1
2873      * StringUtils.indexOfAnyBut(*, null)                              = -1
2874      * StringUtils.indexOfAnyBut(*, [])                                = -1
2875      * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2876      * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
2877      * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
2878 
2879      * </pre>
2880      *
2881      * @param cs  the CharSequence to check, may be null
2882      * @param searchChars  the chars to search for, may be null
2883      * @return the index of any of the chars, -1 if no match or null input
2884      * @since 2.0
2885      * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2886      */
2887     public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2888         if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2889             return INDEX_NOT_FOUND;
2890         }
2891         final int csLen = cs.length();
2892         final int csLast = csLen - 1;
2893         final int searchLen = searchChars.length;
2894         final int searchLast = searchLen - 1;
2895         outer:
2896         for (int i = 0; i < csLen; i++) {
2897             final char ch = cs.charAt(i);
2898             for (int j = 0; j < searchLen; j++) {
2899                 if (searchChars[j] == ch) {
2900                     if (i >= csLast || j >= searchLast || !Character.isHighSurrogate(ch)) {
2901                         continue outer;
2902                     }
2903                     if (searchChars[j + 1] == cs.charAt(i + 1)) {
2904                         continue outer;
2905                     }
2906                 }
2907             }
2908             return i;
2909         }
2910         return INDEX_NOT_FOUND;
2911     }
2912 
2913     /**
2914      * Search a CharSequence to find the first index of any
2915      * character not in the given set of characters.
2916      *
2917      * <p>A {@code null} CharSequence will return {@code -1}.
2918      * A {@code null} or empty search string will return {@code -1}.</p>
2919      *
2920      * <pre>
2921      * StringUtils.indexOfAnyBut(null, *)            = -1
2922      * StringUtils.indexOfAnyBut("", *)              = -1
2923      * StringUtils.indexOfAnyBut(*, null)            = -1
2924      * StringUtils.indexOfAnyBut(*, "")              = -1
2925      * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2926      * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
2927      * StringUtils.indexOfAnyBut("aba", "ab")        = -1
2928      * </pre>
2929      *
2930      * @param seq  the CharSequence to check, may be null
2931      * @param searchChars  the chars to search for, may be null
2932      * @return the index of any of the chars, -1 if no match or null input
2933      * @since 2.0
2934      * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2935      */
2936     public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2937         if (isEmpty(seq) || isEmpty(searchChars)) {
2938             return INDEX_NOT_FOUND;
2939         }
2940         final int strLen = seq.length();
2941         for (int i = 0; i < strLen; i++) {
2942             final char ch = seq.charAt(i);
2943             final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2944             if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2945                 final char ch2 = seq.charAt(i + 1);
2946                 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2947                     return i;
2948                 }
2949             } else if (!chFound) {
2950                 return i;
2951             }
2952         }
2953         return INDEX_NOT_FOUND;
2954     }
2955 
2956     /**
2957      * Compares all CharSequences in an array and returns the index at which the
2958      * CharSequences begin to differ.
2959      *
2960      * <p>For example,
2961      * {@code indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7}</p>
2962      *
2963      * <pre>
2964      * StringUtils.indexOfDifference(null) = -1
2965      * StringUtils.indexOfDifference(new String[] {}) = -1
2966      * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
2967      * StringUtils.indexOfDifference(new String[] {null, null}) = -1
2968      * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
2969      * StringUtils.indexOfDifference(new String[] {"", null}) = 0
2970      * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
2971      * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
2972      * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
2973      * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
2974      * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
2975      * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
2976      * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
2977      * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
2978      * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
2979      * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
2980      * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
2981      * </pre>
2982      *
2983      * @param css  array of CharSequences, entries may be null
2984      * @return the index where the strings begin to differ; -1 if they are all equal
2985      * @since 2.4
2986      * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
2987      */
2988     public static int indexOfDifference(final CharSequence... css) {
2989         if (ArrayUtils.getLength(css) <= 1) {
2990             return INDEX_NOT_FOUND;
2991         }
2992         boolean anyStringNull = false;
2993         boolean allStringsNull = true;
2994         final int arrayLen = css.length;
2995         int shortestStrLen = Integer.MAX_VALUE;
2996         int longestStrLen = 0;
2997 
2998         // find the min and max string lengths; this avoids checking to make
2999         // sure we are not exceeding the length of the string each time through
3000         // the bottom loop.
3001         for (final CharSequence cs : css) {
3002             if (cs == null) {
3003                 anyStringNull = true;
3004                 shortestStrLen = 0;
3005             } else {
3006                 allStringsNull = false;
3007                 shortestStrLen = Math.min(cs.length(), shortestStrLen);
3008                 longestStrLen = Math.max(cs.length(), longestStrLen);
3009             }
3010         }
3011 
3012         // handle lists containing all nulls or all empty strings
3013         if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
3014             return INDEX_NOT_FOUND;
3015         }
3016 
3017         // handle lists containing some nulls or some empty strings
3018         if (shortestStrLen == 0) {
3019             return 0;
3020         }
3021 
3022         // find the position with the first difference across all strings
3023         int firstDiff = -1;
3024         for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
3025             final char comparisonChar = css[0].charAt(stringPos);
3026             for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
3027                 if (css[arrayPos].charAt(stringPos) != comparisonChar) {
3028                     firstDiff = stringPos;
3029                     break;
3030                 }
3031             }
3032             if (firstDiff != -1) {
3033                 break;
3034             }
3035         }
3036 
3037         if (firstDiff == -1 && shortestStrLen != longestStrLen) {
3038             // we compared all of the characters up to the length of the
3039             // shortest string and didn't find a match, but the string lengths
3040             // vary, so return the length of the shortest string.
3041             return shortestStrLen;
3042         }
3043         return firstDiff;
3044     }
3045 
3046     /**
3047      * Compares two CharSequences, and returns the index at which the
3048      * CharSequences begin to differ.
3049      *
3050      * <p>For example,
3051      * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
3052      *
3053      * <pre>
3054      * StringUtils.indexOfDifference(null, null) = -1
3055      * StringUtils.indexOfDifference("", "") = -1
3056      * StringUtils.indexOfDifference("", "abc") = 0
3057      * StringUtils.indexOfDifference("abc", "") = 0
3058      * StringUtils.indexOfDifference("abc", "abc") = -1
3059      * StringUtils.indexOfDifference("ab", "abxyz") = 2
3060      * StringUtils.indexOfDifference("abcde", "abxyz") = 2
3061      * StringUtils.indexOfDifference("abcde", "xyz") = 0
3062      * </pre>
3063      *
3064      * @param cs1  the first CharSequence, may be null
3065      * @param cs2  the second CharSequence, may be null
3066      * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
3067      * @since 2.0
3068      * @since 3.0 Changed signature from indexOfDifference(String, String) to
3069      * indexOfDifference(CharSequence, CharSequence)
3070      */
3071     public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
3072         if (cs1 == cs2) {
3073             return INDEX_NOT_FOUND;
3074         }
3075         if (cs1 == null || cs2 == null) {
3076             return 0;
3077         }
3078         int i;
3079         for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
3080             if (cs1.charAt(i) != cs2.charAt(i)) {
3081                 break;
3082             }
3083         }
3084         if (i < cs2.length() || i < cs1.length()) {
3085             return i;
3086         }
3087         return INDEX_NOT_FOUND;
3088     }
3089 
3090     /**
3091      * Case in-sensitive find of the first index within a CharSequence.
3092      *
3093      * <p>A {@code null} CharSequence will return {@code -1}.
3094      * A negative start position is treated as zero.
3095      * An empty ("") search CharSequence always matches.
3096      * A start position greater than the string length only matches
3097      * an empty search CharSequence.</p>
3098      *
3099      * <pre>
3100      * StringUtils.indexOfIgnoreCase(null, *)          = -1
3101      * StringUtils.indexOfIgnoreCase(*, null)          = -1
3102      * StringUtils.indexOfIgnoreCase("", "")           = 0
3103      * StringUtils.indexOfIgnoreCase(" ", " ")         = 0
3104      * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
3105      * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
3106      * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
3107      * </pre>
3108      *
3109      * @param str  the CharSequence to check, may be null
3110      * @param searchStr  the CharSequence to find, may be null
3111      * @return the first index of the search CharSequence,
3112      *  -1 if no match or {@code null} string input
3113      * @since 2.5
3114      * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
3115      */
3116     public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
3117         return indexOfIgnoreCase(str, searchStr, 0);
3118     }
3119 
3120     /**
3121      * Case in-sensitive find of the first index within a CharSequence
3122      * from the specified position.
3123      *
3124      * <p>A {@code null} CharSequence will return {@code -1}.
3125      * A negative start position is treated as zero.
3126      * An empty ("") search CharSequence always matches.
3127      * A start position greater than the string length only matches
3128      * an empty search CharSequence.</p>
3129      *
3130      * <pre>
3131      * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
3132      * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
3133      * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
3134      * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
3135      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
3136      * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
3137      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
3138      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
3139      * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
3140      * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
3141      * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
3142      * </pre>
3143      *
3144      * @param str  the CharSequence to check, may be null
3145      * @param searchStr  the CharSequence to find, may be null
3146      * @param startPos  the start position, negative treated as zero
3147      * @return the first index of the search CharSequence (always &ge; startPos),
3148      *  -1 if no match or {@code null} string input
3149      * @since 2.5
3150      * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
3151      */
3152     public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
3153         if (str == null || searchStr == null) {
3154             return INDEX_NOT_FOUND;
3155         }
3156         if (startPos < 0) {
3157             startPos = 0;
3158         }
3159         final int endLimit = str.length() - searchStr.length() + 1;
3160         if (startPos > endLimit) {
3161             return INDEX_NOT_FOUND;
3162         }
3163         if (searchStr.length() == 0) {
3164             return startPos;
3165         }
3166         for (int i = startPos; i < endLimit; i++) {
3167             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
3168                 return i;
3169             }
3170         }
3171         return INDEX_NOT_FOUND;
3172     }
3173 
3174     /**
3175      * Checks if all of the CharSequences are empty (""), null or whitespace only.
3176      *
3177      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3178      *
3179      * <pre>
3180      * StringUtils.isAllBlank(null)             = true
3181      * StringUtils.isAllBlank(null, "foo")      = false
3182      * StringUtils.isAllBlank(null, null)       = true
3183      * StringUtils.isAllBlank("", "bar")        = false
3184      * StringUtils.isAllBlank("bob", "")        = false
3185      * StringUtils.isAllBlank("  bob  ", null)  = false
3186      * StringUtils.isAllBlank(" ", "bar")       = false
3187      * StringUtils.isAllBlank("foo", "bar")     = false
3188      * StringUtils.isAllBlank(new String[] {})  = true
3189      * </pre>
3190      *
3191      * @param css  the CharSequences to check, may be null or empty
3192      * @return {@code true} if all of the CharSequences are empty or null or whitespace only
3193      * @since 3.6
3194      */
3195     public static boolean isAllBlank(final CharSequence... css) {
3196         if (ArrayUtils.isEmpty(css)) {
3197             return true;
3198         }
3199         for (final CharSequence cs : css) {
3200             if (isNotBlank(cs)) {
3201                return false;
3202             }
3203         }
3204         return true;
3205     }
3206 
3207     /**
3208      * Checks if all of the CharSequences are empty ("") or null.
3209      *
3210      * <pre>
3211      * StringUtils.isAllEmpty(null)             = true
3212      * StringUtils.isAllEmpty(null, "")         = true
3213      * StringUtils.isAllEmpty(new String[] {})  = true
3214      * StringUtils.isAllEmpty(null, "foo")      = false
3215      * StringUtils.isAllEmpty("", "bar")        = false
3216      * StringUtils.isAllEmpty("bob", "")        = false
3217      * StringUtils.isAllEmpty("  bob  ", null)  = false
3218      * StringUtils.isAllEmpty(" ", "bar")       = false
3219      * StringUtils.isAllEmpty("foo", "bar")     = false
3220      * </pre>
3221      *
3222      * @param css  the CharSequences to check, may be null or empty
3223      * @return {@code true} if all of the CharSequences are empty or null
3224      * @since 3.6
3225      */
3226     public static boolean isAllEmpty(final CharSequence... css) {
3227         if (ArrayUtils.isEmpty(css)) {
3228             return true;
3229         }
3230         for (final CharSequence cs : css) {
3231             if (isNotEmpty(cs)) {
3232                 return false;
3233             }
3234         }
3235         return true;
3236     }
3237 
3238     /**
3239      * Checks if the CharSequence contains only lowercase characters.
3240      *
3241      * <p>{@code null} will return {@code false}.
3242      * An empty CharSequence (length()=0) will return {@code false}.</p>
3243      *
3244      * <pre>
3245      * StringUtils.isAllLowerCase(null)   = false
3246      * StringUtils.isAllLowerCase("")     = false
3247      * StringUtils.isAllLowerCase("  ")   = false
3248      * StringUtils.isAllLowerCase("abc")  = true
3249      * StringUtils.isAllLowerCase("abC")  = false
3250      * StringUtils.isAllLowerCase("ab c") = false
3251      * StringUtils.isAllLowerCase("ab1c") = false
3252      * StringUtils.isAllLowerCase("ab/c") = false
3253      * </pre>
3254      *
3255      * @param cs  the CharSequence to check, may be null
3256      * @return {@code true} if only contains lowercase characters, and is non-null
3257      * @since 2.5
3258      * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
3259      */
3260     public static boolean isAllLowerCase(final CharSequence cs) {
3261         if (isEmpty(cs)) {
3262             return false;
3263         }
3264         final int sz = cs.length();
3265         for (int i = 0; i < sz; i++) {
3266             if (!Character.isLowerCase(cs.charAt(i))) {
3267                 return false;
3268             }
3269         }
3270         return true;
3271     }
3272 
3273     /**
3274      * Checks if the CharSequence contains only uppercase characters.
3275      *
3276      * <p>{@code null} will return {@code false}.
3277      * An empty String (length()=0) will return {@code false}.</p>
3278      *
3279      * <pre>
3280      * StringUtils.isAllUpperCase(null)   = false
3281      * StringUtils.isAllUpperCase("")     = false
3282      * StringUtils.isAllUpperCase("  ")   = false
3283      * StringUtils.isAllUpperCase("ABC")  = true
3284      * StringUtils.isAllUpperCase("aBC")  = false
3285      * StringUtils.isAllUpperCase("A C")  = false
3286      * StringUtils.isAllUpperCase("A1C")  = false
3287      * StringUtils.isAllUpperCase("A/C")  = false
3288      * </pre>
3289      *
3290      * @param cs the CharSequence to check, may be null
3291      * @return {@code true} if only contains uppercase characters, and is non-null
3292      * @since 2.5
3293      * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
3294      */
3295     public static boolean isAllUpperCase(final CharSequence cs) {
3296         if (isEmpty(cs)) {
3297             return false;
3298         }
3299         final int sz = cs.length();
3300         for (int i = 0; i < sz; i++) {
3301             if (!Character.isUpperCase(cs.charAt(i))) {
3302                 return false;
3303             }
3304         }
3305         return true;
3306     }
3307 
3308     /**
3309      * Checks if the CharSequence contains only Unicode letters.
3310      *
3311      * <p>{@code null} will return {@code false}.
3312      * An empty CharSequence (length()=0) will return {@code false}.</p>
3313      *
3314      * <pre>
3315      * StringUtils.isAlpha(null)   = false
3316      * StringUtils.isAlpha("")     = false
3317      * StringUtils.isAlpha("  ")   = false
3318      * StringUtils.isAlpha("abc")  = true
3319      * StringUtils.isAlpha("ab2c") = false
3320      * StringUtils.isAlpha("ab-c") = false
3321      * </pre>
3322      *
3323      * @param cs  the CharSequence to check, may be null
3324      * @return {@code true} if only contains letters, and is non-null
3325      * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
3326      * @since 3.0 Changed "" to return false and not true
3327      */
3328     public static boolean isAlpha(final CharSequence cs) {
3329         if (isEmpty(cs)) {
3330             return false;
3331         }
3332         final int sz = cs.length();
3333         for (int i = 0; i < sz; i++) {
3334             if (!Character.isLetter(cs.charAt(i))) {
3335                 return false;
3336             }
3337         }
3338         return true;
3339     }
3340 
3341     /**
3342      * Checks if the CharSequence contains only Unicode letters or digits.
3343      *
3344      * <p>{@code null} will return {@code false}.
3345      * An empty CharSequence (length()=0) will return {@code false}.</p>
3346      *
3347      * <pre>
3348      * StringUtils.isAlphanumeric(null)   = false
3349      * StringUtils.isAlphanumeric("")     = false
3350      * StringUtils.isAlphanumeric("  ")   = false
3351      * StringUtils.isAlphanumeric("abc")  = true
3352      * StringUtils.isAlphanumeric("ab c") = false
3353      * StringUtils.isAlphanumeric("ab2c") = true
3354      * StringUtils.isAlphanumeric("ab-c") = false
3355      * </pre>
3356      *
3357      * @param cs  the CharSequence to check, may be null
3358      * @return {@code true} if only contains letters or digits,
3359      *  and is non-null
3360      * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
3361      * @since 3.0 Changed "" to return false and not true
3362      */
3363     public static boolean isAlphanumeric(final CharSequence cs) {
3364         if (isEmpty(cs)) {
3365             return false;
3366         }
3367         final int sz = cs.length();
3368         for (int i = 0; i < sz; i++) {
3369             if (!Character.isLetterOrDigit(cs.charAt(i))) {
3370                 return false;
3371             }
3372         }
3373         return true;
3374     }
3375 
3376     /**
3377      * Checks if the CharSequence contains only Unicode letters, digits
3378      * or space ({@code ' '}).
3379      *
3380      * <p>{@code null} will return {@code false}.
3381      * An empty CharSequence (length()=0) will return {@code true}.</p>
3382      *
3383      * <pre>
3384      * StringUtils.isAlphanumericSpace(null)   = false
3385      * StringUtils.isAlphanumericSpace("")     = true
3386      * StringUtils.isAlphanumericSpace("  ")   = true
3387      * StringUtils.isAlphanumericSpace("abc")  = true
3388      * StringUtils.isAlphanumericSpace("ab c") = true
3389      * StringUtils.isAlphanumericSpace("ab2c") = true
3390      * StringUtils.isAlphanumericSpace("ab-c") = false
3391      * </pre>
3392      *
3393      * @param cs  the CharSequence to check, may be null
3394      * @return {@code true} if only contains letters, digits or space,
3395      *  and is non-null
3396      * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
3397      */
3398     public static boolean isAlphanumericSpace(final CharSequence cs) {
3399         if (cs == null) {
3400             return false;
3401         }
3402         final int sz = cs.length();
3403         for (int i = 0; i < sz; i++) {
3404             final char nowChar = cs.charAt(i);
3405             if (nowChar != ' ' && !Character.isLetterOrDigit(nowChar) ) {
3406                 return false;
3407             }
3408         }
3409         return true;
3410     }
3411 
3412     /**
3413      * Checks if the CharSequence contains only Unicode letters and
3414      * space (' ').
3415      *
3416      * <p>{@code null} will return {@code false}
3417      * An empty CharSequence (length()=0) will return {@code true}.</p>
3418      *
3419      * <pre>
3420      * StringUtils.isAlphaSpace(null)   = false
3421      * StringUtils.isAlphaSpace("")     = true
3422      * StringUtils.isAlphaSpace("  ")   = true
3423      * StringUtils.isAlphaSpace("abc")  = true
3424      * StringUtils.isAlphaSpace("ab c") = true
3425      * StringUtils.isAlphaSpace("ab2c") = false
3426      * StringUtils.isAlphaSpace("ab-c") = false
3427      * </pre>
3428      *
3429      * @param cs  the CharSequence to check, may be null
3430      * @return {@code true} if only contains letters and space,
3431      *  and is non-null
3432      * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
3433      */
3434     public static boolean isAlphaSpace(final CharSequence cs) {
3435         if (cs == null) {
3436             return false;
3437         }
3438         final int sz = cs.length();
3439         for (int i = 0; i < sz; i++) {
3440             final char nowChar = cs.charAt(i);
3441             if (nowChar != ' ' && !Character.isLetter(nowChar)) {
3442                 return false;
3443             }
3444         }
3445         return true;
3446     }
3447 
3448     /**
3449      * Checks if any of the CharSequences are empty ("") or null or whitespace only.
3450      *
3451      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3452      *
3453      * <pre>
3454      * StringUtils.isAnyBlank((String) null)    = true
3455      * StringUtils.isAnyBlank((String[]) null)  = false
3456      * StringUtils.isAnyBlank(null, "foo")      = true
3457      * StringUtils.isAnyBlank(null, null)       = true
3458      * StringUtils.isAnyBlank("", "bar")        = true
3459      * StringUtils.isAnyBlank("bob", "")        = true
3460      * StringUtils.isAnyBlank("  bob  ", null)  = true
3461      * StringUtils.isAnyBlank(" ", "bar")       = true
3462      * StringUtils.isAnyBlank(new String[] {})  = false
3463      * StringUtils.isAnyBlank(new String[]{""}) = true
3464      * StringUtils.isAnyBlank("foo", "bar")     = false
3465      * </pre>
3466      *
3467      * @param css  the CharSequences to check, may be null or empty
3468      * @return {@code true} if any of the CharSequences are empty or null or whitespace only
3469      * @since 3.2
3470      */
3471     public static boolean isAnyBlank(final CharSequence... css) {
3472         if (ArrayUtils.isEmpty(css)) {
3473             return false;
3474         }
3475         for (final CharSequence cs : css) {
3476             if (isBlank(cs)) {
3477                 return true;
3478             }
3479         }
3480         return false;
3481     }
3482 
3483     /**
3484      * Checks if any of the CharSequences are empty ("") or null.
3485      *
3486      * <pre>
3487      * StringUtils.isAnyEmpty((String) null)    = true
3488      * StringUtils.isAnyEmpty((String[]) null)  = false
3489      * StringUtils.isAnyEmpty(null, "foo")      = true
3490      * StringUtils.isAnyEmpty("", "bar")        = true
3491      * StringUtils.isAnyEmpty("bob", "")        = true
3492      * StringUtils.isAnyEmpty("  bob  ", null)  = true
3493      * StringUtils.isAnyEmpty(" ", "bar")       = false
3494      * StringUtils.isAnyEmpty("foo", "bar")     = false
3495      * StringUtils.isAnyEmpty(new String[]{})   = false
3496      * StringUtils.isAnyEmpty(new String[]{""}) = true
3497      * </pre>
3498      *
3499      * @param css  the CharSequences to check, may be null or empty
3500      * @return {@code true} if any of the CharSequences are empty or null
3501      * @since 3.2
3502      */
3503     public static boolean isAnyEmpty(final CharSequence... css) {
3504         if (ArrayUtils.isEmpty(css)) {
3505             return false;
3506         }
3507         for (final CharSequence cs : css) {
3508             if (isEmpty(cs)) {
3509                 return true;
3510             }
3511         }
3512         return false;
3513     }
3514 
3515     /**
3516      * Checks if the CharSequence contains only ASCII printable characters.
3517      *
3518      * <p>{@code null} will return {@code false}.
3519      * An empty CharSequence (length()=0) will return {@code true}.</p>
3520      *
3521      * <pre>
3522      * StringUtils.isAsciiPrintable(null)     = false
3523      * StringUtils.isAsciiPrintable("")       = true
3524      * StringUtils.isAsciiPrintable(" ")      = true
3525      * StringUtils.isAsciiPrintable("Ceki")   = true
3526      * StringUtils.isAsciiPrintable("ab2c")   = true
3527      * StringUtils.isAsciiPrintable("!ab-c~") = true
3528      * StringUtils.isAsciiPrintable("\u0020") = true
3529      * StringUtils.isAsciiPrintable("\u0021") = true
3530      * StringUtils.isAsciiPrintable("\u007e") = true
3531      * StringUtils.isAsciiPrintable("\u007f") = false
3532      * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
3533      * </pre>
3534      *
3535      * @param cs the CharSequence to check, may be null
3536      * @return {@code true} if every character is in the range
3537      *  32 through 126
3538      * @since 2.1
3539      * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
3540      */
3541     public static boolean isAsciiPrintable(final CharSequence cs) {
3542         if (cs == null) {
3543             return false;
3544         }
3545         final int sz = cs.length();
3546         for (int i = 0; i < sz; i++) {
3547             if (!CharUtils.isAsciiPrintable(cs.charAt(i))) {
3548                 return false;
3549             }
3550         }
3551         return true;
3552     }
3553 
3554     /**
3555      * Checks if a CharSequence is empty (""), null or whitespace only.
3556      *
3557      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3558      *
3559      * <pre>
3560      * StringUtils.isBlank(null)      = true
3561      * StringUtils.isBlank("")        = true
3562      * StringUtils.isBlank(" ")       = true
3563      * StringUtils.isBlank("bob")     = false
3564      * StringUtils.isBlank("  bob  ") = false
3565      * </pre>
3566      *
3567      * @param cs  the CharSequence to check, may be null
3568      * @return {@code true} if the CharSequence is null, empty or whitespace only
3569      * @since 2.0
3570      * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
3571      */
3572     public static boolean isBlank(final CharSequence cs) {
3573         final int strLen = length(cs);
3574         if (strLen == 0) {
3575             return true;
3576         }
3577         for (int i = 0; i < strLen; i++) {
3578             if (!Character.isWhitespace(cs.charAt(i))) {
3579                 return false;
3580             }
3581         }
3582         return true;
3583     }
3584 
3585     /**
3586      * Checks if a CharSequence is empty ("") or null.
3587      *
3588      * <pre>
3589      * StringUtils.isEmpty(null)      = true
3590      * StringUtils.isEmpty("")        = true
3591      * StringUtils.isEmpty(" ")       = false
3592      * StringUtils.isEmpty("bob")     = false
3593      * StringUtils.isEmpty("  bob  ") = false
3594      * </pre>
3595      *
3596      * <p>NOTE: This method changed in Lang version 2.0.
3597      * It no longer trims the CharSequence.
3598      * That functionality is available in isBlank().</p>
3599      *
3600      * @param cs  the CharSequence to check, may be null
3601      * @return {@code true} if the CharSequence is empty or null
3602      * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
3603      */
3604     public static boolean isEmpty(final CharSequence cs) {
3605         return cs == null || cs.length() == 0;
3606     }
3607 
3608     /**
3609      * Checks if the CharSequence contains mixed casing of both uppercase and lowercase characters.
3610      *
3611      * <p>{@code null} will return {@code false}. An empty CharSequence ({@code length()=0}) will return
3612      * {@code false}.</p>
3613      *
3614      * <pre>
3615      * StringUtils.isMixedCase(null)    = false
3616      * StringUtils.isMixedCase("")      = false
3617      * StringUtils.isMixedCase(" ")     = false
3618      * StringUtils.isMixedCase("ABC")   = false
3619      * StringUtils.isMixedCase("abc")   = false
3620      * StringUtils.isMixedCase("aBc")   = true
3621      * StringUtils.isMixedCase("A c")   = true
3622      * StringUtils.isMixedCase("A1c")   = true
3623      * StringUtils.isMixedCase("a/C")   = true
3624      * StringUtils.isMixedCase("aC\t")  = true
3625      * </pre>
3626      *
3627      * @param cs the CharSequence to check, may be null
3628      * @return {@code true} if the CharSequence contains both uppercase and lowercase characters
3629      * @since 3.5
3630      */
3631     public static boolean isMixedCase(final CharSequence cs) {
3632         if (isEmpty(cs) || cs.length() == 1) {
3633             return false;
3634         }
3635         boolean containsUppercase = false;
3636         boolean containsLowercase = false;
3637         final int sz = cs.length();
3638         for (int i = 0; i < sz; i++) {
3639             final char nowChar = cs.charAt(i);
3640             if (Character.isUpperCase(nowChar)) {
3641                 containsUppercase = true;
3642             } else if (Character.isLowerCase(nowChar)) {
3643                 containsLowercase = true;
3644             }
3645             if (containsUppercase && containsLowercase) {
3646                 return true;
3647             }
3648         }
3649         return false;
3650     }
3651 
3652     /**
3653      * Checks if none of the CharSequences are empty (""), null or whitespace only.
3654      *
3655      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3656      *
3657      * <pre>
3658      * StringUtils.isNoneBlank((String) null)    = false
3659      * StringUtils.isNoneBlank((String[]) null)  = true
3660      * StringUtils.isNoneBlank(null, "foo")      = false
3661      * StringUtils.isNoneBlank(null, null)       = false
3662      * StringUtils.isNoneBlank("", "bar")        = false
3663      * StringUtils.isNoneBlank("bob", "")        = false
3664      * StringUtils.isNoneBlank("  bob  ", null)  = false
3665      * StringUtils.isNoneBlank(" ", "bar")       = false
3666      * StringUtils.isNoneBlank(new String[] {})  = true
3667      * StringUtils.isNoneBlank(new String[]{""}) = false
3668      * StringUtils.isNoneBlank("foo", "bar")     = true
3669      * </pre>
3670      *
3671      * @param css  the CharSequences to check, may be null or empty
3672      * @return {@code true} if none of the CharSequences are empty or null or whitespace only
3673      * @since 3.2
3674      */
3675     public static boolean isNoneBlank(final CharSequence... css) {
3676       return !isAnyBlank(css);
3677     }
3678 
3679     /**
3680      * Checks if none of the CharSequences are empty ("") or null.
3681      *
3682      * <pre>
3683      * StringUtils.isNoneEmpty((String) null)    = false
3684      * StringUtils.isNoneEmpty((String[]) null)  = true
3685      * StringUtils.isNoneEmpty(null, "foo")      = false
3686      * StringUtils.isNoneEmpty("", "bar")        = false
3687      * StringUtils.isNoneEmpty("bob", "")        = false
3688      * StringUtils.isNoneEmpty("  bob  ", null)  = false
3689      * StringUtils.isNoneEmpty(new String[] {})  = true
3690      * StringUtils.isNoneEmpty(new String[]{""}) = false
3691      * StringUtils.isNoneEmpty(" ", "bar")       = true
3692      * StringUtils.isNoneEmpty("foo", "bar")     = true
3693      * </pre>
3694      *
3695      * @param css  the CharSequences to check, may be null or empty
3696      * @return {@code true} if none of the CharSequences are empty or null
3697      * @since 3.2
3698      */
3699     public static boolean isNoneEmpty(final CharSequence... css) {
3700       return !isAnyEmpty(css);
3701     }
3702 
3703     /**
3704      * Checks if a CharSequence is not empty (""), not null and not whitespace only.
3705      *
3706      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3707      *
3708      * <pre>
3709      * StringUtils.isNotBlank(null)      = false
3710      * StringUtils.isNotBlank("")        = false
3711      * StringUtils.isNotBlank(" ")       = false
3712      * StringUtils.isNotBlank("bob")     = true
3713      * StringUtils.isNotBlank("  bob  ") = true
3714      * </pre>
3715      *
3716      * @param cs  the CharSequence to check, may be null
3717      * @return {@code true} if the CharSequence is
3718      *  not empty and not null and not whitespace only
3719      * @since 2.0
3720      * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
3721      */
3722     public static boolean isNotBlank(final CharSequence cs) {
3723         return !isBlank(cs);
3724     }
3725 
3726     /**
3727      * Checks if a CharSequence is not empty ("") and not null.
3728      *
3729      * <pre>
3730      * StringUtils.isNotEmpty(null)      = false
3731      * StringUtils.isNotEmpty("")        = false
3732      * StringUtils.isNotEmpty(" ")       = true
3733      * StringUtils.isNotEmpty("bob")     = true
3734      * StringUtils.isNotEmpty("  bob  ") = true
3735      * </pre>
3736      *
3737      * @param cs  the CharSequence to check, may be null
3738      * @return {@code true} if the CharSequence is not empty and not null
3739      * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
3740      */
3741     public static boolean isNotEmpty(final CharSequence cs) {
3742         return !isEmpty(cs);
3743     }
3744 
3745     /**
3746      * Checks if the CharSequence contains only Unicode digits.
3747      * A decimal point is not a Unicode digit and returns false.
3748      *
3749      * <p>{@code null} will return {@code false}.
3750      * An empty CharSequence (length()=0) will return {@code false}.</p>
3751      *
3752      * <p>Note that the method does not allow for a leading sign, either positive or negative.
3753      * Also, if a String passes the numeric test, it may still generate a NumberFormatException
3754      * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
3755      * for int or long respectively.</p>
3756      *
3757      * <pre>
3758      * StringUtils.isNumeric(null)   = false
3759      * StringUtils.isNumeric("")     = false
3760      * StringUtils.isNumeric("  ")   = false
3761      * StringUtils.isNumeric("123")  = true
3762      * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
3763      * StringUtils.isNumeric("12 3") = false
3764      * StringUtils.isNumeric("ab2c") = false
3765      * StringUtils.isNumeric("12-3") = false
3766      * StringUtils.isNumeric("12.3") = false
3767      * StringUtils.isNumeric("-123") = false
3768      * StringUtils.isNumeric("+123") = false
3769      * </pre>
3770      *
3771      * @param cs  the CharSequence to check, may be null
3772      * @return {@code true} if only contains digits, and is non-null
3773      * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
3774      * @since 3.0 Changed "" to return false and not true
3775      */
3776     public static boolean isNumeric(final CharSequence cs) {
3777         if (isEmpty(cs)) {
3778             return false;
3779         }
3780         final int sz = cs.length();
3781         for (int i = 0; i < sz; i++) {
3782             if (!Character.isDigit(cs.charAt(i))) {
3783                 return false;
3784             }
3785         }
3786         return true;
3787     }
3788 
3789     /**
3790      * Checks if the CharSequence contains only Unicode digits or space
3791      * ({@code ' '}).
3792      * A decimal point is not a Unicode digit and returns false.
3793      *
3794      * <p>{@code null} will return {@code false}.
3795      * An empty CharSequence (length()=0) will return {@code true}.</p>
3796      *
3797      * <pre>
3798      * StringUtils.isNumericSpace(null)   = false
3799      * StringUtils.isNumericSpace("")     = true
3800      * StringUtils.isNumericSpace("  ")   = true
3801      * StringUtils.isNumericSpace("123")  = true
3802      * StringUtils.isNumericSpace("12 3") = true
3803      * StringUtils.isNumericSpace("\u0967\u0968\u0969")  = true
3804      * StringUtils.isNumericSpace("\u0967\u0968 \u0969")  = true
3805      * StringUtils.isNumericSpace("ab2c") = false
3806      * StringUtils.isNumericSpace("12-3") = false
3807      * StringUtils.isNumericSpace("12.3") = false
3808      * </pre>
3809      *
3810      * @param cs  the CharSequence to check, may be null
3811      * @return {@code true} if only contains digits or space,
3812      *  and is non-null
3813      * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
3814      */
3815     public static boolean isNumericSpace(final CharSequence cs) {
3816         if (cs == null) {
3817             return false;
3818         }
3819         final int sz = cs.length();
3820         for (int i = 0; i < sz; i++) {
3821             final char nowChar = cs.charAt(i);
3822             if (nowChar != ' ' && !Character.isDigit(nowChar)) {
3823                 return false;
3824             }
3825         }
3826         return true;
3827     }
3828 
3829     /**
3830      * Checks if the CharSequence contains only whitespace.
3831      *
3832      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3833      *
3834      * <p>{@code null} will return {@code false}.
3835      * An empty CharSequence (length()=0) will return {@code true}.</p>
3836      *
3837      * <pre>
3838      * StringUtils.isWhitespace(null)   = false
3839      * StringUtils.isWhitespace("")     = true
3840      * StringUtils.isWhitespace("  ")   = true
3841      * StringUtils.isWhitespace("abc")  = false
3842      * StringUtils.isWhitespace("ab2c") = false
3843      * StringUtils.isWhitespace("ab-c") = false
3844      * </pre>
3845      *
3846      * @param cs  the CharSequence to check, may be null
3847      * @return {@code true} if only contains whitespace, and is non-null
3848      * @since 2.0
3849      * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
3850      */
3851     public static boolean isWhitespace(final CharSequence cs) {
3852         if (cs == null) {
3853             return false;
3854         }
3855         final int sz = cs.length();
3856         for (int i = 0; i < sz; i++) {
3857             if (!Character.isWhitespace(cs.charAt(i))) {
3858                 return false;
3859             }
3860         }
3861         return true;
3862     }
3863 
3864     /**
3865      * Joins the elements of the provided array into a single String containing the provided list of elements.
3866      *
3867      * <p>
3868      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3869      * by empty strings.
3870      * </p>
3871      *
3872      * <pre>
3873      * StringUtils.join(null, *)              = null
3874      * StringUtils.join([], *)                = ""
3875      * StringUtils.join([null], *)            = ""
3876      * StringUtils.join([false, false], ';')  = "false;false"
3877      * </pre>
3878      *
3879      * @param array
3880      *            the array of values to join together, may be null
3881      * @param delimiter
3882      *            the separator character to use
3883      * @return the joined String, {@code null} if null array input
3884      * @since 3.12.0
3885      */
3886     public static String join(final boolean[] array, final char delimiter) {
3887         if (array == null) {
3888             return null;
3889         }
3890         return join(array, delimiter, 0, array.length);
3891     }
3892 
3893     /**
3894      * Joins the elements of the provided array into a single String containing the provided list of elements.
3895      *
3896      * <p>
3897      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3898      * by empty strings.
3899      * </p>
3900      *
3901      * <pre>
3902      * StringUtils.join(null, *)                   = null
3903      * StringUtils.join([], *)                     = ""
3904      * StringUtils.join([null], *)                 = ""
3905      * StringUtils.join([true, false, true], ';')  = "true;false;true"
3906      * </pre>
3907      *
3908      * @param array
3909      *            the array of values to join together, may be null
3910      * @param delimiter
3911      *            the separator character to use
3912      * @param startIndex
3913      *            the first index to start joining from. It is an error to pass in a start index past the end of the
3914      *            array
3915      * @param endIndex
3916      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3917      *            the array
3918      * @return the joined String, {@code null} if null array input
3919      * @since 3.12.0
3920      */
3921     public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) {
3922         if (array == null) {
3923             return null;
3924         }
3925         if (endIndex - startIndex <= 0) {
3926             return EMPTY;
3927         }
3928         final StringBuilder stringBuilder = new StringBuilder(array.length * 5 + array.length - 1);
3929         for (int i = startIndex; i < endIndex; i++) {
3930             stringBuilder
3931                     .append(array[i])
3932                     .append(delimiter);
3933         }
3934         return stringBuilder.substring(0, stringBuilder.length() - 1);
3935     }
3936 
3937     /**
3938      * Joins the elements of the provided array into a single String containing the provided list of elements.
3939      *
3940      * <p>
3941      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3942      * by empty strings.
3943      * </p>
3944      *
3945      * <pre>
3946      * StringUtils.join(null, *)               = null
3947      * StringUtils.join([], *)                 = ""
3948      * StringUtils.join([null], *)             = ""
3949      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3950      * StringUtils.join([1, 2, 3], null) = "123"
3951      * </pre>
3952      *
3953      * @param array
3954      *            the array of values to join together, may be null
3955      * @param delimiter
3956      *            the separator character to use
3957      * @return the joined String, {@code null} if null array input
3958      * @since 3.2
3959      */
3960     public static String join(final byte[] array, final char delimiter) {
3961         if (array == null) {
3962             return null;
3963         }
3964         return join(array, delimiter, 0, array.length);
3965     }
3966 
3967     /**
3968      * Joins the elements of the provided array into a single String containing the provided list of elements.
3969      *
3970      * <p>
3971      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3972      * by empty strings.
3973      * </p>
3974      *
3975      * <pre>
3976      * StringUtils.join(null, *)               = null
3977      * StringUtils.join([], *)                 = ""
3978      * StringUtils.join([null], *)             = ""
3979      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
3980      * StringUtils.join([1, 2, 3], null) = "123"
3981      * </pre>
3982      *
3983      * @param array
3984      *            the array of values to join together, may be null
3985      * @param delimiter
3986      *            the separator character to use
3987      * @param startIndex
3988      *            the first index to start joining from. It is an error to pass in a start index past the end of the
3989      *            array
3990      * @param endIndex
3991      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
3992      *            the array
3993      * @return the joined String, {@code null} if null array input
3994      * @since 3.2
3995      */
3996     public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) {
3997         if (array == null) {
3998             return null;
3999         }
4000         if (endIndex - startIndex <= 0) {
4001             return EMPTY;
4002         }
4003         final StringBuilder stringBuilder = new StringBuilder();
4004         for (int i = startIndex; i < endIndex; i++) {
4005             stringBuilder
4006                     .append(array[i])
4007                     .append(delimiter);
4008         }
4009         return stringBuilder.substring(0, stringBuilder.length() - 1);
4010     }
4011 
4012     /**
4013      * Joins the elements of the provided array into a single String containing the provided list of elements.
4014      *
4015      * <p>
4016      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4017      * by empty strings.
4018      * </p>
4019      *
4020      * <pre>
4021      * StringUtils.join(null, *)               = null
4022      * StringUtils.join([], *)                 = ""
4023      * StringUtils.join([null], *)             = ""
4024      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4025      * StringUtils.join([1, 2, 3], null) = "123"
4026      * </pre>
4027      *
4028      * @param array
4029      *            the array of values to join together, may be null
4030      * @param delimiter
4031      *            the separator character to use
4032      * @return the joined String, {@code null} if null array input
4033      * @since 3.2
4034      */
4035     public static String join(final char[] array, final char delimiter) {
4036         if (array == null) {
4037             return null;
4038         }
4039         return join(array, delimiter, 0, array.length);
4040     }
4041 
4042     /**
4043      * Joins the elements of the provided array into a single String containing the provided list of elements.
4044      *
4045      * <p>
4046      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4047      * by empty strings.
4048      * </p>
4049      *
4050      * <pre>
4051      * StringUtils.join(null, *)               = null
4052      * StringUtils.join([], *)                 = ""
4053      * StringUtils.join([null], *)             = ""
4054      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4055      * StringUtils.join([1, 2, 3], null) = "123"
4056      * </pre>
4057      *
4058      * @param array
4059      *            the array of values to join together, may be null
4060      * @param delimiter
4061      *            the separator character to use
4062      * @param startIndex
4063      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4064      *            array
4065      * @param endIndex
4066      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4067      *            the array
4068      * @return the joined String, {@code null} if null array input
4069      * @since 3.2
4070      */
4071     public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) {
4072         if (array == null) {
4073             return null;
4074         }
4075         if (endIndex - startIndex <= 0) {
4076             return EMPTY;
4077         }
4078         final StringBuilder stringBuilder = new StringBuilder(array.length * 2 - 1);
4079         for (int i = startIndex; i < endIndex; i++) {
4080             stringBuilder
4081                     .append(array[i])
4082                     .append(delimiter);
4083         }
4084         return stringBuilder.substring(0, stringBuilder.length() - 1);
4085     }
4086 
4087     /**
4088      * Joins the elements of the provided array into a single String containing the provided list of elements.
4089      *
4090      * <p>
4091      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4092      * by empty strings.
4093      * </p>
4094      *
4095      * <pre>
4096      * StringUtils.join(null, *)               = null
4097      * StringUtils.join([], *)                 = ""
4098      * StringUtils.join([null], *)             = ""
4099      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4100      * StringUtils.join([1, 2, 3], null) = "123"
4101      * </pre>
4102      *
4103      * @param array
4104      *            the array of values to join together, may be null
4105      * @param delimiter
4106      *            the separator character to use
4107      * @return the joined String, {@code null} if null array input
4108      * @since 3.2
4109      */
4110     public static String join(final double[] array, final char delimiter) {
4111         if (array == null) {
4112             return null;
4113         }
4114         return join(array, delimiter, 0, array.length);
4115     }
4116 
4117     /**
4118      * Joins the elements of the provided array into a single String containing the provided list of elements.
4119      *
4120      * <p>
4121      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4122      * by empty strings.
4123      * </p>
4124      *
4125      * <pre>
4126      * StringUtils.join(null, *)               = null
4127      * StringUtils.join([], *)                 = ""
4128      * StringUtils.join([null], *)             = ""
4129      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4130      * StringUtils.join([1, 2, 3], null) = "123"
4131      * </pre>
4132      *
4133      * @param array
4134      *            the array of values to join together, may be null
4135      * @param delimiter
4136      *            the separator character to use
4137      * @param startIndex
4138      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4139      *            array
4140      * @param endIndex
4141      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4142      *            the array
4143      * @return the joined String, {@code null} if null array input
4144      * @since 3.2
4145      */
4146     public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) {
4147         if (array == null) {
4148             return null;
4149         }
4150         if (endIndex - startIndex <= 0) {
4151             return EMPTY;
4152         }
4153         final StringBuilder stringBuilder = new StringBuilder();
4154         for (int i = startIndex; i < endIndex; i++) {
4155             stringBuilder
4156                     .append(array[i])
4157                     .append(delimiter);
4158         }
4159         return stringBuilder.substring(0, stringBuilder.length() - 1);
4160     }
4161 
4162     /**
4163      * Joins the elements of the provided array into a single String containing the provided list of elements.
4164      *
4165      * <p>
4166      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4167      * by empty strings.
4168      * </p>
4169      *
4170      * <pre>
4171      * StringUtils.join(null, *)               = null
4172      * StringUtils.join([], *)                 = ""
4173      * StringUtils.join([null], *)             = ""
4174      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4175      * StringUtils.join([1, 2, 3], null) = "123"
4176      * </pre>
4177      *
4178      * @param array
4179      *            the array of values to join together, may be null
4180      * @param delimiter
4181      *            the separator character to use
4182      * @return the joined String, {@code null} if null array input
4183      * @since 3.2
4184      */
4185     public static String join(final float[] array, final char delimiter) {
4186         if (array == null) {
4187             return null;
4188         }
4189         return join(array, delimiter, 0, array.length);
4190     }
4191 
4192     /**
4193      * Joins the elements of the provided array into a single String containing the provided list of elements.
4194      *
4195      * <p>
4196      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4197      * by empty strings.
4198      * </p>
4199      *
4200      * <pre>
4201      * StringUtils.join(null, *)               = null
4202      * StringUtils.join([], *)                 = ""
4203      * StringUtils.join([null], *)             = ""
4204      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4205      * StringUtils.join([1, 2, 3], null) = "123"
4206      * </pre>
4207      *
4208      * @param array
4209      *            the array of values to join together, may be null
4210      * @param delimiter
4211      *            the separator character to use
4212      * @param startIndex
4213      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4214      *            array
4215      * @param endIndex
4216      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4217      *            the array
4218      * @return the joined String, {@code null} if null array input
4219      * @since 3.2
4220      */
4221     public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) {
4222         if (array == null) {
4223             return null;
4224         }
4225         if (endIndex - startIndex <= 0) {
4226             return EMPTY;
4227         }
4228         final StringBuilder stringBuilder = new StringBuilder();
4229         for (int i = startIndex; i < endIndex; i++) {
4230             stringBuilder
4231                     .append(array[i])
4232                     .append(delimiter);
4233         }
4234         return stringBuilder.substring(0, stringBuilder.length() - 1);
4235     }
4236 
4237     /**
4238      * Joins the elements of the provided array into a single String containing the provided list of elements.
4239      *
4240      * <p>
4241      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4242      * by empty strings.
4243      * </p>
4244      *
4245      * <pre>
4246      * StringUtils.join(null, *)               = null
4247      * StringUtils.join([], *)                 = ""
4248      * StringUtils.join([null], *)             = ""
4249      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4250      * StringUtils.join([1, 2, 3], null) = "123"
4251      * </pre>
4252      *
4253      * @param array
4254      *            the array of values to join together, may be null
4255      * @param separator
4256      *            the separator character to use
4257      * @return the joined String, {@code null} if null array input
4258      * @since 3.2
4259      */
4260     public static String join(final int[] array, final char separator) {
4261         if (array == null) {
4262             return null;
4263         }
4264         return join(array, separator, 0, array.length);
4265     }
4266 
4267     /**
4268      * Joins the elements of the provided array into a single String containing the provided list of elements.
4269      *
4270      * <p>
4271      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4272      * by empty strings.
4273      * </p>
4274      *
4275      * <pre>
4276      * StringUtils.join(null, *)               = null
4277      * StringUtils.join([], *)                 = ""
4278      * StringUtils.join([null], *)             = ""
4279      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4280      * StringUtils.join([1, 2, 3], null) = "123"
4281      * </pre>
4282      *
4283      * @param array
4284      *            the array of values to join together, may be null
4285      * @param delimiter
4286      *            the separator character to use
4287      * @param startIndex
4288      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4289      *            array
4290      * @param endIndex
4291      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4292      *            the array
4293      * @return the joined String, {@code null} if null array input
4294      * @since 3.2
4295      */
4296     public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) {
4297         if (array == null) {
4298             return null;
4299         }
4300         if (endIndex - startIndex <= 0) {
4301             return EMPTY;
4302         }
4303         final StringBuilder stringBuilder = new StringBuilder();
4304         for (int i = startIndex; i < endIndex; i++) {
4305             stringBuilder
4306                     .append(array[i])
4307                     .append(delimiter);
4308         }
4309         return stringBuilder.substring(0, stringBuilder.length() - 1);
4310     }
4311 
4312     /**
4313      * Joins the elements of the provided {@link Iterable} into
4314      * a single String containing the provided elements.
4315      *
4316      * <p>No delimiter is added before or after the list. Null objects or empty
4317      * strings within the iteration are represented by empty strings.</p>
4318      *
4319      * <p>See the examples here: {@link #join(Object[],char)}.</p>
4320      *
4321      * @param iterable  the {@link Iterable} providing the values to join together, may be null
4322      * @param separator  the separator character to use
4323      * @return the joined String, {@code null} if null iterator input
4324      * @since 2.3
4325      */
4326     public static String join(final Iterable<?> iterable, final char separator) {
4327         return iterable != null ? join(iterable.iterator(), separator) : null;
4328     }
4329 
4330     /**
4331      * Joins the elements of the provided {@link Iterable} into
4332      * a single String containing the provided elements.
4333      *
4334      * <p>No delimiter is added before or after the list.
4335      * A {@code null} separator is the same as an empty String ("").</p>
4336      *
4337      * <p>See the examples here: {@link #join(Object[],String)}.</p>
4338      *
4339      * @param iterable  the {@link Iterable} providing the values to join together, may be null
4340      * @param separator  the separator character to use, null treated as ""
4341      * @return the joined String, {@code null} if null iterator input
4342      * @since 2.3
4343      */
4344     public static String join(final Iterable<?> iterable, final String separator) {
4345         return iterable != null ? join(iterable.iterator(), separator) : null;
4346     }
4347 
4348     /**
4349      * Joins the elements of the provided {@link Iterator} into
4350      * a single String containing the provided elements.
4351      *
4352      * <p>No delimiter is added before or after the list. Null objects or empty
4353      * strings within the iteration are represented by empty strings.</p>
4354      *
4355      * <p>See the examples here: {@link #join(Object[],char)}.</p>
4356      *
4357      * @param iterator  the {@link Iterator} of values to join together, may be null
4358      * @param separator  the separator character to use
4359      * @return the joined String, {@code null} if null iterator input
4360      * @since 2.0
4361      */
4362     public static String join(final Iterator<?> iterator, final char separator) {
4363         // handle null, zero and one elements before building a buffer
4364         if (iterator == null) {
4365             return null;
4366         }
4367         if (!iterator.hasNext()) {
4368             return EMPTY;
4369         }
4370         return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(String.valueOf(separator)), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
4371     }
4372 
4373     /**
4374      * Joins the elements of the provided {@link Iterator} into
4375      * a single String containing the provided elements.
4376      *
4377      * <p>No delimiter is added before or after the list.
4378      * A {@code null} separator is the same as an empty String ("").</p>
4379      *
4380      * <p>See the examples here: {@link #join(Object[],String)}.</p>
4381      *
4382      * @param iterator  the {@link Iterator} of values to join together, may be null
4383      * @param separator  the separator character to use, null treated as ""
4384      * @return the joined String, {@code null} if null iterator input
4385      */
4386     public static String join(final Iterator<?> iterator, final String separator) {
4387         // handle null, zero and one elements before building a buffer
4388         if (iterator == null) {
4389             return null;
4390         }
4391         if (!iterator.hasNext()) {
4392             return EMPTY;
4393         }
4394         return Streams.of(iterator).collect(LangCollectors.joining(toStringOrEmpty(separator), EMPTY, EMPTY, StringUtils::toStringOrEmpty));
4395     }
4396 
4397     /**
4398      * Joins the elements of the provided {@link List} into a single String
4399      * containing the provided list of elements.
4400      *
4401      * <p>No delimiter is added before or after the list.
4402      * Null objects or empty strings within the array are represented by
4403      * empty strings.</p>
4404      *
4405      * <pre>
4406      * StringUtils.join(null, *)               = null
4407      * StringUtils.join([], *)                 = ""
4408      * StringUtils.join([null], *)             = ""
4409      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4410      * StringUtils.join(["a", "b", "c"], null) = "abc"
4411      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4412      * </pre>
4413      *
4414      * @param list  the {@link List} of values to join together, may be null
4415      * @param separator  the separator character to use
4416      * @param startIndex the first index to start joining from.  It is
4417      * an error to pass in a start index past the end of the list
4418      * @param endIndex the index to stop joining from (exclusive). It is
4419      * an error to pass in an end index past the end of the list
4420      * @return the joined String, {@code null} if null list input
4421      * @since 3.8
4422      */
4423     public static String join(final List<?> list, final char separator, final int startIndex, final int endIndex) {
4424         if (list == null) {
4425             return null;
4426         }
4427         final int noOfItems = endIndex - startIndex;
4428         if (noOfItems <= 0) {
4429             return EMPTY;
4430         }
4431         final List<?> subList = list.subList(startIndex, endIndex);
4432         return join(subList.iterator(), separator);
4433     }
4434 
4435     /**
4436      * Joins the elements of the provided {@link List} into a single String
4437      * containing the provided list of elements.
4438      *
4439      * <p>No delimiter is added before or after the list.
4440      * Null objects or empty strings within the array are represented by
4441      * empty strings.</p>
4442      *
4443      * <pre>
4444      * StringUtils.join(null, *)               = null
4445      * StringUtils.join([], *)                 = ""
4446      * StringUtils.join([null], *)             = ""
4447      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4448      * StringUtils.join(["a", "b", "c"], null) = "abc"
4449      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4450      * </pre>
4451      *
4452      * @param list  the {@link List} of values to join together, may be null
4453      * @param separator  the separator character to use
4454      * @param startIndex the first index to start joining from.  It is
4455      * an error to pass in a start index past the end of the list
4456      * @param endIndex the index to stop joining from (exclusive). It is
4457      * an error to pass in an end index past the end of the list
4458      * @return the joined String, {@code null} if null list input
4459      * @since 3.8
4460      */
4461     public static String join(final List<?> list, final String separator, final int startIndex, final int endIndex) {
4462         if (list == null) {
4463             return null;
4464         }
4465         final int noOfItems = endIndex - startIndex;
4466         if (noOfItems <= 0) {
4467             return EMPTY;
4468         }
4469         final List<?> subList = list.subList(startIndex, endIndex);
4470         return join(subList.iterator(), separator);
4471     }
4472 
4473 
4474     /**
4475      * Joins the elements of the provided array into a single String containing the provided list of elements.
4476      *
4477      * <p>
4478      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4479      * by empty strings.
4480      * </p>
4481      *
4482      * <pre>
4483      * StringUtils.join(null, *)               = null
4484      * StringUtils.join([], *)                 = ""
4485      * StringUtils.join([null], *)             = ""
4486      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4487      * StringUtils.join([1, 2, 3], null) = "123"
4488      * </pre>
4489      *
4490      * @param array
4491      *            the array of values to join together, may be null
4492      * @param separator
4493      *            the separator character to use
4494      * @return the joined String, {@code null} if null array input
4495      * @since 3.2
4496      */
4497     public static String join(final long[] array, final char separator) {
4498         if (array == null) {
4499             return null;
4500         }
4501         return join(array, separator, 0, array.length);
4502     }
4503 
4504     /**
4505      * Joins the elements of the provided array into a single String containing the provided list of elements.
4506      *
4507      * <p>
4508      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4509      * by empty strings.
4510      * </p>
4511      *
4512      * <pre>
4513      * StringUtils.join(null, *)               = null
4514      * StringUtils.join([], *)                 = ""
4515      * StringUtils.join([null], *)             = ""
4516      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4517      * StringUtils.join([1, 2, 3], null) = "123"
4518      * </pre>
4519      *
4520      * @param array
4521      *            the array of values to join together, may be null
4522      * @param delimiter
4523      *            the separator character to use
4524      * @param startIndex
4525      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4526      *            array
4527      * @param endIndex
4528      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4529      *            the array
4530      * @return the joined String, {@code null} if null array input
4531      * @since 3.2
4532      */
4533     public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) {
4534         if (array == null) {
4535             return null;
4536         }
4537         if (endIndex - startIndex <= 0) {
4538             return EMPTY;
4539         }
4540         final StringBuilder stringBuilder = new StringBuilder();
4541         for (int i = startIndex; i < endIndex; i++) {
4542             stringBuilder
4543                     .append(array[i])
4544                     .append(delimiter);
4545         }
4546         return stringBuilder.substring(0, stringBuilder.length() - 1);
4547     }
4548 
4549     /**
4550      * Joins the elements of the provided array into a single String
4551      * containing the provided list of elements.
4552      *
4553      * <p>No delimiter is added before or after the list.
4554      * Null objects or empty strings within the array are represented by
4555      * empty strings.</p>
4556      *
4557      * <pre>
4558      * StringUtils.join(null, *)               = null
4559      * StringUtils.join([], *)                 = ""
4560      * StringUtils.join([null], *)             = ""
4561      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4562      * StringUtils.join(["a", "b", "c"], null) = "abc"
4563      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4564      * </pre>
4565      *
4566      * @param array  the array of values to join together, may be null
4567      * @param delimiter  the separator character to use
4568      * @return the joined String, {@code null} if null array input
4569      * @since 2.0
4570      */
4571     public static String join(final Object[] array, final char delimiter) {
4572         if (array == null) {
4573             return null;
4574         }
4575         return join(array, delimiter, 0, array.length);
4576     }
4577 
4578     /**
4579      * Joins the elements of the provided array into a single String
4580      * containing the provided list of elements.
4581      *
4582      * <p>No delimiter is added before or after the list.
4583      * Null objects or empty strings within the array are represented by
4584      * empty strings.</p>
4585      *
4586      * <pre>
4587      * StringUtils.join(null, *)               = null
4588      * StringUtils.join([], *)                 = ""
4589      * StringUtils.join([null], *)             = ""
4590      * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
4591      * StringUtils.join(["a", "b", "c"], null) = "abc"
4592      * StringUtils.join([null, "", "a"], ';')  = ";;a"
4593      * </pre>
4594      *
4595      * @param array  the array of values to join together, may be null
4596      * @param delimiter  the separator character to use
4597      * @param startIndex the first index to start joining from.  It is
4598      * an error to pass in a start index past the end of the array
4599      * @param endIndex the index to stop joining from (exclusive). It is
4600      * an error to pass in an end index past the end of the array
4601      * @return the joined String, {@code null} if null array input
4602      * @since 2.0
4603      */
4604     public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
4605         return join(array, String.valueOf(delimiter), startIndex, endIndex);
4606     }
4607 
4608     /**
4609      * Joins the elements of the provided array into a single String
4610      * containing the provided list of elements.
4611      *
4612      * <p>No delimiter is added before or after the list.
4613      * A {@code null} separator is the same as an empty String ("").
4614      * Null objects or empty strings within the array are represented by
4615      * empty strings.</p>
4616      *
4617      * <pre>
4618      * StringUtils.join(null, *)                = null
4619      * StringUtils.join([], *)                  = ""
4620      * StringUtils.join([null], *)              = ""
4621      * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
4622      * StringUtils.join(["a", "b", "c"], null)  = "abc"
4623      * StringUtils.join(["a", "b", "c"], "")    = "abc"
4624      * StringUtils.join([null, "", "a"], ',')   = ",,a"
4625      * </pre>
4626      *
4627      * @param array  the array of values to join together, may be null
4628      * @param delimiter  the separator character to use, null treated as ""
4629      * @return the joined String, {@code null} if null array input
4630      */
4631     public static String join(final Object[] array, final String delimiter) {
4632         return array != null ? join(array, toStringOrEmpty(delimiter), 0, array.length) : null;
4633     }
4634 
4635     /**
4636      * Joins the elements of the provided array into a single String
4637      * containing the provided list of elements.
4638      *
4639      * <p>No delimiter is added before or after the list.
4640      * A {@code null} separator is the same as an empty String ("").
4641      * Null objects or empty strings within the array are represented by
4642      * empty strings.</p>
4643      *
4644      * <pre>
4645      * StringUtils.join(null, *, *, *)                = null
4646      * StringUtils.join([], *, *, *)                  = ""
4647      * StringUtils.join([null], *, *, *)              = ""
4648      * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
4649      * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
4650      * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
4651      * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
4652      * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
4653      * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
4654      * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
4655      * </pre>
4656      *
4657      * @param array  the array of values to join together, may be null
4658      * @param delimiter  the separator character to use, null treated as ""
4659      * @param startIndex the first index to start joining from.
4660      * @param endIndex the index to stop joining from (exclusive).
4661      * @return the joined String, {@code null} if null array input; or the empty string
4662      * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4663      * {@code endIndex - startIndex}
4664      * @throws ArrayIndexOutOfBoundsException ife<br>
4665      * {@code startIndex < 0} or <br>
4666      * {@code startIndex >= array.length()} or <br>
4667      * {@code endIndex < 0} or <br>
4668      * {@code endIndex > array.length()}
4669      */
4670     public static String join(final Object[] array, final String delimiter, final int startIndex, final int endIndex) {
4671         return array != null ? Streams.of(array).skip(startIndex).limit(Math.max(0, endIndex - startIndex))
4672             .collect(LangCollectors.joining(delimiter, EMPTY, EMPTY, StringUtils::toStringOrEmpty)) : null;
4673     }
4674 
4675     /**
4676      * Joins the elements of the provided array into a single String containing the provided list of elements.
4677      *
4678      * <p>
4679      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4680      * by empty strings.
4681      * </p>
4682      *
4683      * <pre>
4684      * StringUtils.join(null, *)               = null
4685      * StringUtils.join([], *)                 = ""
4686      * StringUtils.join([null], *)             = ""
4687      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4688      * StringUtils.join([1, 2, 3], null) = "123"
4689      * </pre>
4690      *
4691      * @param array
4692      *            the array of values to join together, may be null
4693      * @param delimiter
4694      *            the separator character to use
4695      * @return the joined String, {@code null} if null array input
4696      * @since 3.2
4697      */
4698     public static String join(final short[] array, final char delimiter) {
4699         if (array == null) {
4700             return null;
4701         }
4702         return join(array, delimiter, 0, array.length);
4703     }
4704 
4705     /**
4706      * Joins the elements of the provided array into a single String containing the provided list of elements.
4707      *
4708      * <p>
4709      * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4710      * by empty strings.
4711      * </p>
4712      *
4713      * <pre>
4714      * StringUtils.join(null, *)               = null
4715      * StringUtils.join([], *)                 = ""
4716      * StringUtils.join([null], *)             = ""
4717      * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
4718      * StringUtils.join([1, 2, 3], null) = "123"
4719      * </pre>
4720      *
4721      * @param array
4722      *            the array of values to join together, may be null
4723      * @param delimiter
4724      *            the separator character to use
4725      * @param startIndex
4726      *            the first index to start joining from. It is an error to pass in a start index past the end of the
4727      *            array
4728      * @param endIndex
4729      *            the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4730      *            the array
4731      * @return the joined String, {@code null} if null array input
4732      * @since 3.2
4733      */
4734     public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) {
4735         if (array == null) {
4736             return null;
4737         }
4738         if (endIndex - startIndex <= 0) {
4739             return EMPTY;
4740         }
4741         final StringBuilder stringBuilder = new StringBuilder();
4742         for (int i = startIndex; i < endIndex; i++) {
4743             stringBuilder
4744                     .append(array[i])
4745                     .append(delimiter);
4746         }
4747         return stringBuilder.substring(0, stringBuilder.length() - 1);
4748     }
4749 
4750     /**
4751      * Joins the elements of the provided array into a single String
4752      * containing the provided list of elements.
4753      *
4754      * <p>No separator is added to the joined String.
4755      * Null objects or empty strings within the array are represented by
4756      * empty strings.</p>
4757      *
4758      * <pre>
4759      * StringUtils.join(null)            = null
4760      * StringUtils.join([])              = ""
4761      * StringUtils.join([null])          = ""
4762      * StringUtils.join(["a", "b", "c"]) = "abc"
4763      * StringUtils.join([null, "", "a"]) = "a"
4764      * </pre>
4765      *
4766      * @param <T> the specific type of values to join together
4767      * @param elements  the values to join together, may be null
4768      * @return the joined String, {@code null} if null array input
4769      * @since 2.0
4770      * @since 3.0 Changed signature to use varargs
4771      */
4772     @SafeVarargs
4773     public static <T> String join(final T... elements) {
4774         return join(elements, null);
4775     }
4776 
4777     /**
4778      * Joins the elements of the provided varargs into a
4779      * single String containing the provided elements.
4780      *
4781      * <p>No delimiter is added before or after the list.
4782      * {@code null} elements and separator are treated as empty Strings ("").</p>
4783      *
4784      * <pre>
4785      * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
4786      * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
4787      * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
4788      * StringUtils.joinWith(null, {"a", "b"})       = "ab"
4789      * </pre>
4790      *
4791      * @param delimiter the separator character to use, null treated as ""
4792      * @param array the varargs providing the values to join together. {@code null} elements are treated as ""
4793      * @return the joined String.
4794      * @throws IllegalArgumentException if a null varargs is provided
4795      * @since 3.5
4796      */
4797     public static String joinWith(final String delimiter, final Object... array) {
4798         if (array == null) {
4799             throw new IllegalArgumentException("Object varargs must not be null");
4800         }
4801         return join(array, delimiter);
4802     }
4803 
4804     /**
4805      * Finds the last index within a CharSequence, handling {@code null}.
4806      * This method uses {@link String#lastIndexOf(String)} if possible.
4807      *
4808      * <p>A {@code null} CharSequence will return {@code -1}.</p>
4809      *
4810      * <pre>
4811      * StringUtils.lastIndexOf(null, *)          = -1
4812      * StringUtils.lastIndexOf(*, null)          = -1
4813      * StringUtils.lastIndexOf("", "")           = 0
4814      * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
4815      * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
4816      * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
4817      * StringUtils.lastIndexOf("aabaabaa", "")   = 8
4818      * </pre>
4819      *
4820      * @param seq  the CharSequence to check, may be null
4821      * @param searchSeq  the CharSequence to find, may be null
4822      * @return the last index of the search String,
4823      *  -1 if no match or {@code null} string input
4824      * @since 2.0
4825      * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
4826      */
4827     public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
4828         if (seq == null) {
4829             return INDEX_NOT_FOUND;
4830         }
4831         return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
4832     }
4833 
4834     /**
4835      * Finds the last index within a CharSequence, handling {@code null}.
4836      * This method uses {@link String#lastIndexOf(String, int)} if possible.
4837      *
4838      * <p>A {@code null} CharSequence will return {@code -1}.
4839      * A negative start position returns {@code -1}.
4840      * An empty ("") search CharSequence always matches unless the start position is negative.
4841      * A start position greater than the string length searches the whole string.
4842      * The search starts at the startPos and works backwards; matches starting after the start
4843      * position are ignored.
4844      * </p>
4845      *
4846      * <pre>
4847      * StringUtils.lastIndexOf(null, *, *)          = -1
4848      * StringUtils.lastIndexOf(*, null, *)          = -1
4849      * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
4850      * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
4851      * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
4852      * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
4853      * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
4854      * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
4855      * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
4856      * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
4857      * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
4858      * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
4859      * </pre>
4860      *
4861      * @param seq  the CharSequence to check, may be null
4862      * @param searchSeq  the CharSequence to find, may be null
4863      * @param startPos  the start position, negative treated as zero
4864      * @return the last index of the search CharSequence (always &le; startPos),
4865      *  -1 if no match or {@code null} string input
4866      * @since 2.0
4867      * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
4868      */
4869     public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
4870         return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
4871     }
4872 
4873     /**
4874      * Returns the index within {@code seq} of the last occurrence of
4875      * the specified character. For values of {@code searchChar} in the
4876      * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
4877      * units) returned is the largest value <i>k</i> such that:
4878      * <blockquote><pre>
4879      * this.charAt(<i>k</i>) == searchChar
4880      * </pre></blockquote>
4881      * is true. For other values of {@code searchChar}, it is the
4882      * largest value <i>k</i> such that:
4883      * <blockquote><pre>
4884      * this.codePointAt(<i>k</i>) == searchChar
4885      * </pre></blockquote>
4886      * is true.  In either case, if no such character occurs in this
4887      * string, then {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4888      * {@link CharSequence} will return {@code -1}. The
4889      * {@code seq} {@link CharSequence} object is searched backwards
4890      * starting at the last character.
4891      *
4892      * <pre>
4893      * StringUtils.lastIndexOf(null, *)         = -1
4894      * StringUtils.lastIndexOf("", *)           = -1
4895      * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
4896      * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
4897      * </pre>
4898      *
4899      * @param seq  the {@link CharSequence} to check, may be null
4900      * @param searchChar  the character to find
4901      * @return the last index of the search character,
4902      *  -1 if no match or {@code null} string input
4903      * @since 2.0
4904      * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
4905      * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like {@link String}
4906      */
4907     public static int lastIndexOf(final CharSequence seq, final int searchChar) {
4908         if (isEmpty(seq)) {
4909             return INDEX_NOT_FOUND;
4910         }
4911         return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
4912     }
4913 
4914     /**
4915      * Returns the index within {@code seq} of the last occurrence of
4916      * the specified character, searching backward starting at the
4917      * specified index. For values of {@code searchChar} in the range
4918      * from 0 to 0xFFFF (inclusive), the index returned is the largest
4919      * value <i>k</i> such that:
4920      * <blockquote><pre>
4921      * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
4922      * </pre></blockquote>
4923      * is true. For other values of {@code searchChar}, it is the
4924      * largest value <i>k</i> such that:
4925      * <blockquote><pre>
4926      * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
4927      * </pre></blockquote>
4928      * is true. In either case, if no such character occurs in {@code seq}
4929      * at or before position {@code startPos}, then
4930      * {@code -1} is returned. Furthermore, a {@code null} or empty ("")
4931      * {@link CharSequence} will return {@code -1}. A start position greater
4932      * than the string length searches the whole string.
4933      * The search starts at the {@code startPos} and works backwards;
4934      * matches starting after the start position are ignored.
4935      *
4936      * <p>All indices are specified in {@code char} values
4937      * (Unicode code units).
4938      *
4939      * <pre>
4940      * StringUtils.lastIndexOf(null, *, *)          = -1
4941      * StringUtils.lastIndexOf("", *,  *)           = -1
4942      * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
4943      * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
4944      * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
4945      * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
4946      * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
4947      * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
4948      * </pre>
4949      *
4950      * @param seq  the CharSequence to check, may be null
4951      * @param searchChar  the character to find
4952      * @param startPos  the start position
4953      * @return the last index of the search character (always &le; startPos),
4954      *  -1 if no match or {@code null} string input
4955      * @since 2.0
4956      * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
4957      */
4958     public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
4959         if (isEmpty(seq)) {
4960             return INDEX_NOT_FOUND;
4961         }
4962         return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
4963     }
4964 
4965     /**
4966      * Find the latest index of any substring in a set of potential substrings.
4967      *
4968      * <p>A {@code null} CharSequence will return {@code -1}.
4969      * A {@code null} search array will return {@code -1}.
4970      * A {@code null} or zero length search array entry will be ignored,
4971      * but a search array containing "" will return the length of {@code str}
4972      * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
4973      *
4974      * <pre>
4975      * StringUtils.lastIndexOfAny(null, *)                    = -1
4976      * StringUtils.lastIndexOfAny(*, null)                    = -1
4977      * StringUtils.lastIndexOfAny(*, [])                      = -1
4978      * StringUtils.lastIndexOfAny(*, [null])                  = -1
4979      * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab", "cd"]) = 6
4980      * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd", "ab"]) = 6
4981      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4982      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", "op"]) = -1
4983      * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn", ""])   = 10
4984      * </pre>
4985      *
4986      * @param str  the CharSequence to check, may be null
4987      * @param searchStrs  the CharSequences to search for, may be null
4988      * @return the last index of any of the CharSequences, -1 if no match
4989      * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
4990      */
4991     public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
4992         if (str == null || searchStrs == null) {
4993             return INDEX_NOT_FOUND;
4994         }
4995         int ret = INDEX_NOT_FOUND;
4996         int tmp;
4997         for (final CharSequence search : searchStrs) {
4998             if (search == null) {
4999                 continue;
5000             }
5001             tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
5002             if (tmp > ret) {
5003                 ret = tmp;
5004             }
5005         }
5006         return ret;
5007     }
5008 
5009     /**
5010      * Case in-sensitive find of the last index within a CharSequence.
5011      *
5012      * <p>A {@code null} CharSequence will return {@code -1}.
5013      * A negative start position returns {@code -1}.
5014      * An empty ("") search CharSequence always matches unless the start position is negative.
5015      * A start position greater than the string length searches the whole string.</p>
5016      *
5017      * <pre>
5018      * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
5019      * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
5020      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
5021      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
5022      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
5023      * </pre>
5024      *
5025      * @param str  the CharSequence to check, may be null
5026      * @param searchStr  the CharSequence to find, may be null
5027      * @return the first index of the search CharSequence,
5028      *  -1 if no match or {@code null} string input
5029      * @since 2.5
5030      * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
5031      */
5032     public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
5033         if (str == null || searchStr == null) {
5034             return INDEX_NOT_FOUND;
5035         }
5036         return lastIndexOfIgnoreCase(str, searchStr, str.length());
5037     }
5038 
5039     /**
5040      * Case in-sensitive find of the last index within a CharSequence
5041      * from the specified position.
5042      *
5043      * <p>A {@code null} CharSequence will return {@code -1}.
5044      * A negative start position returns {@code -1}.
5045      * An empty ("") search CharSequence always matches unless the start position is negative.
5046      * A start position greater than the string length searches the whole string.
5047      * The search starts at the startPos and works backwards; matches starting after the start
5048      * position are ignored.
5049      * </p>
5050      *
5051      * <pre>
5052      * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
5053      * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
5054      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
5055      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
5056      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
5057      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
5058      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
5059      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
5060      * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
5061      * </pre>
5062      *
5063      * @param str  the CharSequence to check, may be null
5064      * @param searchStr  the CharSequence to find, may be null
5065      * @param startPos  the start position
5066      * @return the last index of the search CharSequence (always &le; startPos),
5067      *  -1 if no match or {@code null} input
5068      * @since 2.5
5069      * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
5070      */
5071     public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
5072         if (str == null || searchStr == null) {
5073             return INDEX_NOT_FOUND;
5074         }
5075         final int searchStrLength = searchStr.length();
5076         final int strLength = str.length();
5077         if (startPos > strLength - searchStrLength) {
5078             startPos = strLength - searchStrLength;
5079         }
5080         if (startPos < 0) {
5081             return INDEX_NOT_FOUND;
5082         }
5083         if (searchStrLength == 0) {
5084             return startPos;
5085         }
5086 
5087         for (int i = startPos; i >= 0; i--) {
5088             if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStrLength)) {
5089                 return i;
5090             }
5091         }
5092         return INDEX_NOT_FOUND;
5093     }
5094 
5095     /**
5096      * Finds the n-th last index within a String, handling {@code null}.
5097      * This method uses {@link String#lastIndexOf(String)}.
5098      *
5099      * <p>A {@code null} String will return {@code -1}.</p>
5100      *
5101      * <pre>
5102      * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
5103      * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
5104      * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
5105      * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
5106      * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
5107      * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
5108      * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
5109      * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
5110      * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
5111      * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
5112      * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
5113      * </pre>
5114      *
5115      * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
5116      *
5117      * <pre>
5118      *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
5119      * </pre>
5120      *
5121      * @param str  the CharSequence to check, may be null
5122      * @param searchStr  the CharSequence to find, may be null
5123      * @param ordinal  the n-th last {@code searchStr} to find
5124      * @return the n-th last index of the search CharSequence,
5125      *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5126      * @since 2.5
5127      * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
5128      */
5129     public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5130         return ordinalIndexOf(str, searchStr, ordinal, true);
5131     }
5132 
5133     /**
5134      * Gets the leftmost {@code len} characters of a String.
5135      *
5136      * <p>If {@code len} characters are not available, or the
5137      * String is {@code null}, the String will be returned without
5138      * an exception. An empty String is returned if len is negative.</p>
5139      *
5140      * <pre>
5141      * StringUtils.left(null, *)    = null
5142      * StringUtils.left(*, -ve)     = ""
5143      * StringUtils.left("", *)      = ""
5144      * StringUtils.left("abc", 0)   = ""
5145      * StringUtils.left("abc", 2)   = "ab"
5146      * StringUtils.left("abc", 4)   = "abc"
5147      * </pre>
5148      *
5149      * @param str  the String to get the leftmost characters from, may be null
5150      * @param len  the length of the required String
5151      * @return the leftmost characters, {@code null} if null String input
5152      */
5153     public static String left(final String str, final int len) {
5154         if (str == null) {
5155             return null;
5156         }
5157         if (len < 0) {
5158             return EMPTY;
5159         }
5160         if (str.length() <= len) {
5161             return str;
5162         }
5163         return str.substring(0, len);
5164     }
5165 
5166     /**
5167      * Left pad a String with spaces (' ').
5168      *
5169      * <p>The String is padded to the size of {@code size}.</p>
5170      *
5171      * <pre>
5172      * StringUtils.leftPad(null, *)   = null
5173      * StringUtils.leftPad("", 3)     = "   "
5174      * StringUtils.leftPad("bat", 3)  = "bat"
5175      * StringUtils.leftPad("bat", 5)  = "  bat"
5176      * StringUtils.leftPad("bat", 1)  = "bat"
5177      * StringUtils.leftPad("bat", -1) = "bat"
5178      * </pre>
5179      *
5180      * @param str  the String to pad out, may be null
5181      * @param size  the size to pad to
5182      * @return left padded String or original String if no padding is necessary,
5183      *  {@code null} if null String input
5184      */
5185     public static String leftPad(final String str, final int size) {
5186         return leftPad(str, size, ' ');
5187     }
5188 
5189     /**
5190      * Left pad a String with a specified character.
5191      *
5192      * <p>Pad to a size of {@code size}.</p>
5193      *
5194      * <pre>
5195      * StringUtils.leftPad(null, *, *)     = null
5196      * StringUtils.leftPad("", 3, 'z')     = "zzz"
5197      * StringUtils.leftPad("bat", 3, 'z')  = "bat"
5198      * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
5199      * StringUtils.leftPad("bat", 1, 'z')  = "bat"
5200      * StringUtils.leftPad("bat", -1, 'z') = "bat"
5201      * </pre>
5202      *
5203      * @param str  the String to pad out, may be null
5204      * @param size  the size to pad to
5205      * @param padChar  the character to pad with
5206      * @return left padded String or original String if no padding is necessary,
5207      *  {@code null} if null String input
5208      * @since 2.0
5209      */
5210     public static String leftPad(final String str, final int size, final char padChar) {
5211         if (str == null) {
5212             return null;
5213         }
5214         final int pads = size - str.length();
5215         if (pads <= 0) {
5216             return str; // returns original String when possible
5217         }
5218         if (pads > PAD_LIMIT) {
5219             return leftPad(str, size, String.valueOf(padChar));
5220         }
5221         return repeat(padChar, pads).concat(str);
5222     }
5223 
5224     /**
5225      * Left pad a String with a specified String.
5226      *
5227      * <p>Pad to a size of {@code size}.</p>
5228      *
5229      * <pre>
5230      * StringUtils.leftPad(null, *, *)      = null
5231      * StringUtils.leftPad("", 3, "z")      = "zzz"
5232      * StringUtils.leftPad("bat", 3, "yz")  = "bat"
5233      * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
5234      * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
5235      * StringUtils.leftPad("bat", 1, "yz")  = "bat"
5236      * StringUtils.leftPad("bat", -1, "yz") = "bat"
5237      * StringUtils.leftPad("bat", 5, null)  = "  bat"
5238      * StringUtils.leftPad("bat", 5, "")    = "  bat"
5239      * </pre>
5240      *
5241      * @param str  the String to pad out, may be null
5242      * @param size  the size to pad to
5243      * @param padStr  the String to pad with, null or empty treated as single space
5244      * @return left padded String or original String if no padding is necessary,
5245      *  {@code null} if null String input
5246      */
5247     public static String leftPad(final String str, final int size, String padStr) {
5248         if (str == null) {
5249             return null;
5250         }
5251         if (isEmpty(padStr)) {
5252             padStr = SPACE;
5253         }
5254         final int padLen = padStr.length();
5255         final int strLen = str.length();
5256         final int pads = size - strLen;
5257         if (pads <= 0) {
5258             return str; // returns original String when possible
5259         }
5260         if (padLen == 1 && pads <= PAD_LIMIT) {
5261             return leftPad(str, size, padStr.charAt(0));
5262         }
5263 
5264         if (pads == padLen) {
5265             return padStr.concat(str);
5266         }
5267         if (pads < padLen) {
5268             return padStr.substring(0, pads).concat(str);
5269         }
5270         final char[] padding = new char[pads];
5271         final char[] padChars = padStr.toCharArray();
5272         for (int i = 0; i < pads; i++) {
5273             padding[i] = padChars[i % padLen];
5274         }
5275         return new String(padding).concat(str);
5276     }
5277 
5278     /**
5279      * Gets a CharSequence length or {@code 0} if the CharSequence is
5280      * {@code null}.
5281      *
5282      * @param cs
5283      *            a CharSequence or {@code null}
5284      * @return CharSequence length or {@code 0} if the CharSequence is
5285      *         {@code null}.
5286      * @since 2.4
5287      * @since 3.0 Changed signature from length(String) to length(CharSequence)
5288      */
5289     public static int length(final CharSequence cs) {
5290         return cs == null ? 0 : cs.length();
5291     }
5292 
5293     /**
5294      * Converts a String to lower case as per {@link String#toLowerCase()}.
5295      *
5296      * <p>A {@code null} input String returns {@code null}.</p>
5297      *
5298      * <pre>
5299      * StringUtils.lowerCase(null)  = null
5300      * StringUtils.lowerCase("")    = ""
5301      * StringUtils.lowerCase("aBc") = "abc"
5302      * </pre>
5303      *
5304      * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
5305      * the result of this method is affected by the current locale.
5306      * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
5307      * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
5308      *
5309      * @param str  the String to lower case, may be null
5310      * @return the lower cased String, {@code null} if null String input
5311      */
5312     public static String lowerCase(final String str) {
5313         if (str == null) {
5314             return null;
5315         }
5316         return str.toLowerCase();
5317     }
5318 
5319     /**
5320      * Converts a String to lower case as per {@link String#toLowerCase(Locale)}.
5321      *
5322      * <p>A {@code null} input String returns {@code null}.</p>
5323      *
5324      * <pre>
5325      * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
5326      * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
5327      * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
5328      * </pre>
5329      *
5330      * @param str  the String to lower case, may be null
5331      * @param locale  the locale that defines the case transformation rules, must not be null
5332      * @return the lower cased String, {@code null} if null String input
5333      * @since 2.5
5334      */
5335     public static String lowerCase(final String str, final Locale locale) {
5336         if (str == null) {
5337             return null;
5338         }
5339         return str.toLowerCase(LocaleUtils.toLocale(locale));
5340     }
5341 
5342     private static int[] matches(final CharSequence first, final CharSequence second) {
5343         final CharSequence max;
5344         final CharSequence min;
5345         if (first.length() > second.length()) {
5346             max = first;
5347             min = second;
5348         } else {
5349             max = second;
5350             min = first;
5351         }
5352         final int range = Math.max(max.length() / 2 - 1, 0);
5353         final int[] matchIndexes = new int[min.length()];
5354         Arrays.fill(matchIndexes, -1);
5355         final boolean[] matchFlags = new boolean[max.length()];
5356         int matches = 0;
5357         for (int mi = 0; mi < min.length(); mi++) {
5358             final char c1 = min.charAt(mi);
5359             for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
5360                 if (!matchFlags[xi] && c1 == max.charAt(xi)) {
5361                     matchIndexes[mi] = xi;
5362                     matchFlags[xi] = true;
5363                     matches++;
5364                     break;
5365                 }
5366             }
5367         }
5368         final char[] ms1 = new char[matches];
5369         final char[] ms2 = new char[matches];
5370         for (int i = 0, si = 0; i < min.length(); i++) {
5371             if (matchIndexes[i] != -1) {
5372                 ms1[si] = min.charAt(i);
5373                 si++;
5374             }
5375         }
5376         for (int i = 0, si = 0; i < max.length(); i++) {
5377             if (matchFlags[i]) {
5378                 ms2[si] = max.charAt(i);
5379                 si++;
5380             }
5381         }
5382         int transpositions = 0;
5383         for (int mi = 0; mi < ms1.length; mi++) {
5384             if (ms1[mi] != ms2[mi]) {
5385                 transpositions++;
5386             }
5387         }
5388         int prefix = 0;
5389         for (int mi = 0; mi < min.length(); mi++) {
5390             if (first.charAt(mi) != second.charAt(mi)) {
5391                 break;
5392             }
5393             prefix++;
5394         }
5395         return new int[] { matches, transpositions / 2, prefix, max.length() };
5396     }
5397 
5398     /**
5399      * Gets {@code len} characters from the middle of a String.
5400      *
5401      * <p>If {@code len} characters are not available, the remainder
5402      * of the String will be returned without an exception. If the
5403      * String is {@code null}, {@code null} will be returned.
5404      * An empty String is returned if len is negative or exceeds the
5405      * length of {@code str}.</p>
5406      *
5407      * <pre>
5408      * StringUtils.mid(null, *, *)    = null
5409      * StringUtils.mid(*, *, -ve)     = ""
5410      * StringUtils.mid("", 0, *)      = ""
5411      * StringUtils.mid("abc", 0, 2)   = "ab"
5412      * StringUtils.mid("abc", 0, 4)   = "abc"
5413      * StringUtils.mid("abc", 2, 4)   = "c"
5414      * StringUtils.mid("abc", 4, 2)   = ""
5415      * StringUtils.mid("abc", -2, 2)  = "ab"
5416      * </pre>
5417      *
5418      * @param str  the String to get the characters from, may be null
5419      * @param pos  the position to start from, negative treated as zero
5420      * @param len  the length of the required String
5421      * @return the middle characters, {@code null} if null String input
5422      */
5423     public static String mid(final String str, int pos, final int len) {
5424         if (str == null) {
5425             return null;
5426         }
5427         if (len < 0 || pos > str.length()) {
5428             return EMPTY;
5429         }
5430         if (pos < 0) {
5431             pos = 0;
5432         }
5433         if (str.length() <= pos + len) {
5434             return str.substring(pos);
5435         }
5436         return str.substring(pos, pos + len);
5437     }
5438 
5439     /**
5440      * Similar to <a
5441      * href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize
5442      * -space</a>
5443      *
5444      * <p>
5445      * The function returns the argument string with whitespace normalized by using
5446      * {@code {@link #trim(String)}} to remove leading and trailing whitespace
5447      * and then replacing sequences of whitespace characters by a single space.
5448      * </p>
5449      * In XML Whitespace characters are the same as those allowed by the <a
5450      * href="https://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
5451      * <p>
5452      * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
5453      *
5454      * <p>For reference:</p>
5455      * <ul>
5456      * <li>\x0B = vertical tab</li>
5457      * <li>\f = #xC = form feed</li>
5458      * <li>#x20 = space</li>
5459      * <li>#x9 = \t</li>
5460      * <li>#xA = \n</li>
5461      * <li>#xD = \r</li>
5462      * </ul>
5463      *
5464      * <p>
5465      * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
5466      * normalize. Additionally {@code {@link #trim(String)}} removes control characters (char &lt;= 32) from both
5467      * ends of this String.
5468      * </p>
5469      *
5470      * @see Pattern
5471      * @see #trim(String)
5472      * @see <a
5473      *      href="https://www.w3.org/TR/xpath/#function-normalize-space">https://www.w3.org/TR/xpath/#function-normalize-space</a>
5474      * @param str the source String to normalize whitespaces from, may be null
5475      * @return the modified string with whitespace normalized, {@code null} if null String input
5476      *
5477      * @since 3.0
5478      */
5479     public static String normalizeSpace(final String str) {
5480         // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
5481         // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
5482         if (isEmpty(str)) {
5483             return str;
5484         }
5485         final int size = str.length();
5486         final char[] newChars = new char[size];
5487         int count = 0;
5488         int whitespacesCount = 0;
5489         boolean startWhitespaces = true;
5490         for (int i = 0; i < size; i++) {
5491             final char actualChar = str.charAt(i);
5492             final boolean isWhitespace = Character.isWhitespace(actualChar);
5493             if (isWhitespace) {
5494                 if (whitespacesCount == 0 && !startWhitespaces) {
5495                     newChars[count++] = SPACE.charAt(0);
5496                 }
5497                 whitespacesCount++;
5498             } else {
5499                 startWhitespaces = false;
5500                 newChars[count++] = actualChar == 160 ? 32 : actualChar;
5501                 whitespacesCount = 0;
5502             }
5503         }
5504         if (startWhitespaces) {
5505             return EMPTY;
5506         }
5507         return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
5508     }
5509 
5510     /**
5511      * Finds the n-th index within a CharSequence, handling {@code null}.
5512      * This method uses {@link String#indexOf(String)} if possible.
5513      * <p><b>Note:</b> The code starts looking for a match at the start of the target,
5514      * incrementing the starting index by one after each successful match
5515      * (unless {@code searchStr} is an empty string in which case the position
5516      * is never incremented and {@code 0} is returned immediately).
5517      * This means that matches may overlap.</p>
5518      * <p>A {@code null} CharSequence will return {@code -1}.</p>
5519      *
5520      * <pre>
5521      * StringUtils.ordinalIndexOf(null, *, *)          = -1
5522      * StringUtils.ordinalIndexOf(*, null, *)          = -1
5523      * StringUtils.ordinalIndexOf("", "", *)           = 0
5524      * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
5525      * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
5526      * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
5527      * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
5528      * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
5529      * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
5530      * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
5531      * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
5532      * </pre>
5533      *
5534      * <p>Matches may overlap:</p>
5535      * <pre>
5536      * StringUtils.ordinalIndexOf("ababab", "aba", 1)   = 0
5537      * StringUtils.ordinalIndexOf("ababab", "aba", 2)   = 2
5538      * StringUtils.ordinalIndexOf("ababab", "aba", 3)   = -1
5539      *
5540      * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
5541      * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
5542      * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
5543      * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
5544      * </pre>
5545      *
5546      * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
5547      *
5548      * <pre>
5549      *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
5550      * </pre>
5551      *
5552      * @param str  the CharSequence to check, may be null
5553      * @param searchStr  the CharSequence to find, may be null
5554      * @param ordinal  the n-th {@code searchStr} to find
5555      * @return the n-th index of the search CharSequence,
5556      *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5557      * @since 2.1
5558      * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
5559      */
5560     public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
5561         return ordinalIndexOf(str, searchStr, ordinal, false);
5562     }
5563 
5564     /**
5565      * Finds the n-th index within a String, handling {@code null}.
5566      * This method uses {@link String#indexOf(String)} if possible.
5567      * <p>Note that matches may overlap<p>
5568      *
5569      * <p>A {@code null} CharSequence will return {@code -1}.</p>
5570      *
5571      * @param str  the CharSequence to check, may be null
5572      * @param searchStr  the CharSequence to find, may be null
5573      * @param ordinal  the n-th {@code searchStr} to find, overlapping matches are allowed.
5574      * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
5575      * @return the n-th index of the search CharSequence,
5576      *  {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
5577      */
5578     // Shared code between ordinalIndexOf(String, String, int) and lastOrdinalIndexOf(String, String, int)
5579     private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
5580         if (str == null || searchStr == null || ordinal <= 0) {
5581             return INDEX_NOT_FOUND;
5582         }
5583         if (searchStr.length() == 0) {
5584             return lastIndex ? str.length() : 0;
5585         }
5586         int found = 0;
5587         // set the initial index beyond the end of the string
5588         // this is to allow for the initial index decrement/increment
5589         int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
5590         do {
5591             if (lastIndex) {
5592                 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards through string
5593             } else {
5594                 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
5595             }
5596             if (index < 0) {
5597                 return index;
5598             }
5599             found++;
5600         } while (found < ordinal);
5601         return index;
5602     }
5603 
5604     /**
5605      * Overlays part of a String with another String.
5606      *
5607      * <p>A {@code null} string input returns {@code null}.
5608      * A negative index is treated as zero.
5609      * An index greater than the string length is treated as the string length.
5610      * The start index is always the smaller of the two indices.</p>
5611      *
5612      * <pre>
5613      * StringUtils.overlay(null, *, *, *)            = null
5614      * StringUtils.overlay("", "abc", 0, 0)          = "abc"
5615      * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
5616      * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
5617      * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
5618      * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
5619      * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
5620      * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
5621      * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
5622      * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5623      * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
5624      * </pre>
5625      *
5626      * @param str  the String to do overlaying in, may be null
5627      * @param overlay  the String to overlay, may be null
5628      * @param start  the position to start overlaying at
5629      * @param end  the position to stop overlaying before
5630      * @return overlayed String, {@code null} if null String input
5631      * @since 2.0
5632      */
5633     public static String overlay(final String str, String overlay, int start, int end) {
5634         if (str == null) {
5635             return null;
5636         }
5637         if (overlay == null) {
5638             overlay = EMPTY;
5639         }
5640         final int len = str.length();
5641         if (start < 0) {
5642             start = 0;
5643         }
5644         if (start > len) {
5645             start = len;
5646         }
5647         if (end < 0) {
5648             end = 0;
5649         }
5650         if (end > len) {
5651             end = len;
5652         }
5653         if (start > end) {
5654             final int temp = start;
5655             start = end;
5656             end = temp;
5657         }
5658         return str.substring(0, start) +
5659             overlay +
5660             str.substring(end);
5661     }
5662 
5663     /**
5664      * Prepends the prefix to the start of the string if the string does not
5665      * already start with any of the prefixes.
5666      *
5667      * @param str The string.
5668      * @param prefix The prefix to prepend to the start of the string.
5669      * @param ignoreCase Indicates whether the compare should ignore case.
5670      * @param prefixes Additional prefixes that are valid (optional).
5671      *
5672      * @return A new String if prefix was prepended, the same string otherwise.
5673      */
5674     private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
5675         if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
5676             return str;
5677         }
5678         if (ArrayUtils.isNotEmpty(prefixes)) {
5679             for (final CharSequence p : prefixes) {
5680                 if (startsWith(str, p, ignoreCase)) {
5681                     return str;
5682                 }
5683             }
5684         }
5685         return prefix.toString() + str;
5686     }
5687 
5688     /**
5689      * Prepends the prefix to the start of the string if the string does not
5690      * already start with any of the prefixes.
5691      *
5692      * <pre>
5693      * StringUtils.prependIfMissing(null, null) = null
5694      * StringUtils.prependIfMissing("abc", null) = "abc"
5695      * StringUtils.prependIfMissing("", "xyz") = "xyz"
5696      * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
5697      * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
5698      * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
5699      * </pre>
5700      * <p>With additional prefixes,</p>
5701      * <pre>
5702      * StringUtils.prependIfMissing(null, null, null) = null
5703      * StringUtils.prependIfMissing("abc", null, null) = "abc"
5704      * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
5705      * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5706      * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
5707      * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
5708      * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
5709      * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
5710      * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
5711      * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
5712      * </pre>
5713      *
5714      * @param str The string.
5715      * @param prefix The prefix to prepend to the start of the string.
5716      * @param prefixes Additional prefixes that are valid.
5717      *
5718      * @return A new String if prefix was prepended, the same string otherwise.
5719      *
5720      * @since 3.2
5721      */
5722     public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5723         return prependIfMissing(str, prefix, false, prefixes);
5724     }
5725 
5726     /**
5727      * Prepends the prefix to the start of the string if the string does not
5728      * already start, case-insensitive, with any of the prefixes.
5729      *
5730      * <pre>
5731      * StringUtils.prependIfMissingIgnoreCase(null, null) = null
5732      * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
5733      * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
5734      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
5735      * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
5736      * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
5737      * </pre>
5738      * <p>With additional prefixes,</p>
5739      * <pre>
5740      * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
5741      * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
5742      * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
5743      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
5744      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
5745      * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
5746      * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
5747      * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
5748      * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
5749      * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
5750      * </pre>
5751      *
5752      * @param str The string.
5753      * @param prefix The prefix to prepend to the start of the string.
5754      * @param prefixes Additional prefixes that are valid (optional).
5755      *
5756      * @return A new String if prefix was prepended, the same string otherwise.
5757      *
5758      * @since 3.2
5759      */
5760     public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
5761         return prependIfMissing(str, prefix, true, prefixes);
5762     }
5763 
5764     /**
5765      * Removes all occurrences of a character from within the source string.
5766      *
5767      * <p>A {@code null} source string will return {@code null}.
5768      * An empty ("") source string will return the empty string.</p>
5769      *
5770      * <pre>
5771      * StringUtils.remove(null, *)       = null
5772      * StringUtils.remove("", *)         = ""
5773      * StringUtils.remove("queued", 'u') = "qeed"
5774      * StringUtils.remove("queued", 'z') = "queued"
5775      * </pre>
5776      *
5777      * @param str  the source String to search, may be null
5778      * @param remove  the char to search for and remove, may be null
5779      * @return the substring with the char removed if found,
5780      *  {@code null} if null String input
5781      * @since 2.1
5782      */
5783     public static String remove(final String str, final char remove) {
5784         if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5785             return str;
5786         }
5787         final char[] chars = str.toCharArray();
5788         int pos = 0;
5789         for (int i = 0; i < chars.length; i++) {
5790             if (chars[i] != remove) {
5791                 chars[pos++] = chars[i];
5792             }
5793         }
5794         return new String(chars, 0, pos);
5795     }
5796 
5797     /**
5798      * Removes all occurrences of a substring from within the source string.
5799      *
5800      * <p>A {@code null} source string will return {@code null}.
5801      * An empty ("") source string will return the empty string.
5802      * A {@code null} remove string will return the source string.
5803      * An empty ("") remove string will return the source string.</p>
5804      *
5805      * <pre>
5806      * StringUtils.remove(null, *)        = null
5807      * StringUtils.remove("", *)          = ""
5808      * StringUtils.remove(*, null)        = *
5809      * StringUtils.remove(*, "")          = *
5810      * StringUtils.remove("queued", "ue") = "qd"
5811      * StringUtils.remove("queued", "zz") = "queued"
5812      * </pre>
5813      *
5814      * @param str  the source String to search, may be null
5815      * @param remove  the String to search for and remove, may be null
5816      * @return the substring with the string removed if found,
5817      *  {@code null} if null String input
5818      * @since 2.1
5819      */
5820     public static String remove(final String str, final String remove) {
5821         if (isEmpty(str) || isEmpty(remove)) {
5822             return str;
5823         }
5824         return replace(str, remove, EMPTY, -1);
5825     }
5826 
5827     /**
5828      * Removes each substring of the text String that matches the given regular expression.
5829      *
5830      * This method is a {@code null} safe equivalent to:
5831      * <ul>
5832      *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5833      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5834      * </ul>
5835      *
5836      * <p>A {@code null} reference passed to this method is a no-op.</p>
5837      *
5838      * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5839      * is NOT automatically added.
5840      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5841      * DOTALL is also known as single-line mode in Perl.</p>
5842      *
5843      * <pre>
5844      * StringUtils.removeAll(null, *)      = null
5845      * StringUtils.removeAll("any", (String) null)  = "any"
5846      * StringUtils.removeAll("any", "")    = "any"
5847      * StringUtils.removeAll("any", ".*")  = ""
5848      * StringUtils.removeAll("any", ".+")  = ""
5849      * StringUtils.removeAll("abc", ".?")  = ""
5850      * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\nB"
5851      * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5852      * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
5853      * </pre>
5854      *
5855      * @param text  text to remove from, may be null
5856      * @param regex  the regular expression to which this string is to be matched
5857      * @return  the text with any removes processed,
5858      *              {@code null} if null String input
5859      *
5860      * @throws  java.util.regex.PatternSyntaxException
5861      *              if the regular expression's syntax is invalid
5862      *
5863      * @see #replaceAll(String, String, String)
5864      * @see #removePattern(String, String)
5865      * @see String#replaceAll(String, String)
5866      * @see java.util.regex.Pattern
5867      * @see java.util.regex.Pattern#DOTALL
5868      * @since 3.5
5869      *
5870      * @deprecated Moved to RegExUtils.
5871      */
5872     @Deprecated
5873     public static String removeAll(final String text, final String regex) {
5874         return RegExUtils.removeAll(text, regex);
5875     }
5876 
5877     /**
5878      * Removes a substring only if it is at the end of a source string,
5879      * otherwise returns the source string.
5880      *
5881      * <p>A {@code null} source string will return {@code null}.
5882      * An empty ("") source string will return the empty string.
5883      * A {@code null} search string will return the source string.</p>
5884      *
5885      * <pre>
5886      * StringUtils.removeEnd(null, *)      = null
5887      * StringUtils.removeEnd("", *)        = ""
5888      * StringUtils.removeEnd(*, null)      = *
5889      * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
5890      * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
5891      * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
5892      * StringUtils.removeEnd("abc", "")    = "abc"
5893      * </pre>
5894      *
5895      * @param str  the source String to search, may be null
5896      * @param remove  the String to search for and remove, may be null
5897      * @return the substring with the string removed if found,
5898      *  {@code null} if null String input
5899      * @since 2.1
5900      */
5901     public static String removeEnd(final String str, final String remove) {
5902         if (isEmpty(str) || isEmpty(remove)) {
5903             return str;
5904         }
5905         if (str.endsWith(remove)) {
5906             return str.substring(0, str.length() - remove.length());
5907         }
5908         return str;
5909     }
5910 
5911     /**
5912      * Case insensitive removal of a substring if it is at the end of a source string,
5913      * otherwise returns the source string.
5914      *
5915      * <p>A {@code null} source string will return {@code null}.
5916      * An empty ("") source string will return the empty string.
5917      * A {@code null} search string will return the source string.</p>
5918      *
5919      * <pre>
5920      * StringUtils.removeEndIgnoreCase(null, *)      = null
5921      * StringUtils.removeEndIgnoreCase("", *)        = ""
5922      * StringUtils.removeEndIgnoreCase(*, null)      = *
5923      * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
5924      * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
5925      * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
5926      * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
5927      * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
5928      * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
5929      * </pre>
5930      *
5931      * @param str  the source String to search, may be null
5932      * @param remove  the String to search for (case-insensitive) and remove, may be null
5933      * @return the substring with the string removed if found,
5934      *  {@code null} if null String input
5935      * @since 2.4
5936      */
5937     public static String removeEndIgnoreCase(final String str, final String remove) {
5938         if (isEmpty(str) || isEmpty(remove)) {
5939             return str;
5940         }
5941         if (endsWithIgnoreCase(str, remove)) {
5942             return str.substring(0, str.length() - remove.length());
5943         }
5944         return str;
5945     }
5946 
5947     /**
5948      * Removes the first substring of the text string that matches the given regular expression.
5949      *
5950      * This method is a {@code null} safe equivalent to:
5951      * <ul>
5952      *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5953      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5954      * </ul>
5955      *
5956      * <p>A {@code null} reference passed to this method is a no-op.</p>
5957      *
5958      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5959      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
5960      * DOTALL is also known as single-line mode in Perl.</p>
5961      *
5962      * <pre>
5963      * StringUtils.removeFirst(null, *)      = null
5964      * StringUtils.removeFirst("any", (String) null)  = "any"
5965      * StringUtils.removeFirst("any", "")    = "any"
5966      * StringUtils.removeFirst("any", ".*")  = ""
5967      * StringUtils.removeFirst("any", ".+")  = ""
5968      * StringUtils.removeFirst("abc", ".?")  = "bc"
5969      * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")      = "A\n&lt;__&gt;B"
5970      * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;")  = "AB"
5971      * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
5972      * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
5973      * </pre>
5974      *
5975      * @param text  text to remove from, may be null
5976      * @param regex  the regular expression to which this string is to be matched
5977      * @return  the text with the first replacement processed,
5978      *              {@code null} if null String input
5979      *
5980      * @throws  java.util.regex.PatternSyntaxException
5981      *              if the regular expression's syntax is invalid
5982      *
5983      * @see #replaceFirst(String, String, String)
5984      * @see String#replaceFirst(String, String)
5985      * @see java.util.regex.Pattern
5986      * @see java.util.regex.Pattern#DOTALL
5987      * @since 3.5
5988      *
5989      * @deprecated Moved to RegExUtils.
5990      */
5991     @Deprecated
5992     public static String removeFirst(final String text, final String regex) {
5993         return replaceFirst(text, regex, EMPTY);
5994     }
5995 
5996     /**
5997      * Case insensitive removal of all occurrences of a substring from within
5998      * the source string.
5999      *
6000      * <p>
6001      * A {@code null} source string will return {@code null}. An empty ("")
6002      * source string will return the empty string. A {@code null} remove string
6003      * will return the source string. An empty ("") remove string will return
6004      * the source string.
6005      * </p>
6006      *
6007      * <pre>
6008      * StringUtils.removeIgnoreCase(null, *)        = null
6009      * StringUtils.removeIgnoreCase("", *)          = ""
6010      * StringUtils.removeIgnoreCase(*, null)        = *
6011      * StringUtils.removeIgnoreCase(*, "")          = *
6012      * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
6013      * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
6014      * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
6015      * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
6016      * </pre>
6017      *
6018      * @param str
6019      *            the source String to search, may be null
6020      * @param remove
6021      *            the String to search for (case-insensitive) and remove, may be
6022      *            null
6023      * @return the substring with the string removed if found, {@code null} if
6024      *         null String input
6025      * @since 3.5
6026      */
6027     public static String removeIgnoreCase(final String str, final String remove) {
6028         return replaceIgnoreCase(str, remove, EMPTY, -1);
6029     }
6030 
6031     /**
6032      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
6033      *
6034      * This call is a {@code null} safe equivalent to:
6035      * <ul>
6036      * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
6037      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
6038      * </ul>
6039      *
6040      * <p>A {@code null} reference passed to this method is a no-op.</p>
6041      *
6042      * <pre>
6043      * StringUtils.removePattern(null, *)       = null
6044      * StringUtils.removePattern("any", (String) null)   = "any"
6045      * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;")  = "AB"
6046      * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
6047      * </pre>
6048      *
6049      * @param source
6050      *            the source string
6051      * @param regex
6052      *            the regular expression to which this string is to be matched
6053      * @return The resulting {@link String}
6054      * @see #replacePattern(String, String, String)
6055      * @see String#replaceAll(String, String)
6056      * @see Pattern#DOTALL
6057      * @since 3.2
6058      * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
6059      *
6060      * @deprecated Moved to RegExUtils.
6061      */
6062     @Deprecated
6063     public static String removePattern(final String source, final String regex) {
6064         return RegExUtils.removePattern(source, regex);
6065     }
6066 
6067     /**
6068      * Removes a char only if it is at the beginning of a source string,
6069      * otherwise returns the source string.
6070      *
6071      * <p>A {@code null} source string will return {@code null}.
6072      * An empty ("") source string will return the empty string.
6073      * A {@code null} search char will return the source string.</p>
6074      *
6075      * <pre>
6076      * StringUtils.removeStart(null, *)      = null
6077      * StringUtils.removeStart("", *)        = ""
6078      * StringUtils.removeStart(*, null)      = *
6079      * StringUtils.removeStart("/path", '/') = "path"
6080      * StringUtils.removeStart("path", '/')  = "path"
6081      * StringUtils.removeStart("path", 0)    = "path"
6082      * </pre>
6083      *
6084      * @param str  the source String to search, may be null.
6085      * @param remove  the char to search for and remove.
6086      * @return the substring with the char removed if found,
6087      *  {@code null} if null String input.
6088      * @since 3.13.0
6089      */
6090     public static String removeStart(final String str, final char remove) {
6091         if (isEmpty(str)) {
6092             return str;
6093         }
6094         return str.charAt(0) == remove ? str.substring(1) : str;
6095     }
6096 
6097     /**
6098      * Removes a substring only if it is at the beginning of a source string,
6099      * otherwise returns the source string.
6100      *
6101      * <p>A {@code null} source string will return {@code null}.
6102      * An empty ("") source string will return the empty string.
6103      * A {@code null} search string will return the source string.</p>
6104      *
6105      * <pre>
6106      * StringUtils.removeStart(null, *)      = null
6107      * StringUtils.removeStart("", *)        = ""
6108      * StringUtils.removeStart(*, null)      = *
6109      * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
6110      * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
6111      * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
6112      * StringUtils.removeStart("abc", "")    = "abc"
6113      * </pre>
6114      *
6115      * @param str  the source String to search, may be null
6116      * @param remove  the String to search for and remove, may be null
6117      * @return the substring with the string removed if found,
6118      *  {@code null} if null String input
6119      * @since 2.1
6120      */
6121     public static String removeStart(final String str, final String remove) {
6122         if (isEmpty(str) || isEmpty(remove)) {
6123             return str;
6124         }
6125         if (str.startsWith(remove)) {
6126             return str.substring(remove.length());
6127         }
6128         return str;
6129     }
6130 
6131     /**
6132      * Case insensitive removal of a substring if it is at the beginning of a source string,
6133      * otherwise returns the source string.
6134      *
6135      * <p>A {@code null} source string will return {@code null}.
6136      * An empty ("") source string will return the empty string.
6137      * A {@code null} search string will return the source string.</p>
6138      *
6139      * <pre>
6140      * StringUtils.removeStartIgnoreCase(null, *)      = null
6141      * StringUtils.removeStartIgnoreCase("", *)        = ""
6142      * StringUtils.removeStartIgnoreCase(*, null)      = *
6143      * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
6144      * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
6145      * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
6146      * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
6147      * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
6148      * </pre>
6149      *
6150      * @param str  the source String to search, may be null
6151      * @param remove  the String to search for (case-insensitive) and remove, may be null
6152      * @return the substring with the string removed if found,
6153      *  {@code null} if null String input
6154      * @since 2.4
6155      */
6156     public static String removeStartIgnoreCase(final String str, final String remove) {
6157         if (str != null && startsWithIgnoreCase(str, remove)) {
6158             return str.substring(length(remove));
6159         }
6160         return str;
6161     }
6162 
6163     /**
6164      * Returns padding using the specified delimiter repeated
6165      * to a given length.
6166      *
6167      * <pre>
6168      * StringUtils.repeat('e', 0)  = ""
6169      * StringUtils.repeat('e', 3)  = "eee"
6170      * StringUtils.repeat('e', -2) = ""
6171      * </pre>
6172      *
6173      * <p>Note: this method does not support padding with
6174      * <a href="https://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6175      * as they require a pair of {@code char}s to be represented.
6176      * If you are needing to support full I18N of your applications
6177      * consider using {@link #repeat(String, int)} instead.
6178      * </p>
6179      *
6180      * @param ch  character to repeat
6181      * @param repeat  number of times to repeat char, negative treated as zero
6182      * @return String with repeated character
6183      * @see #repeat(String, int)
6184      */
6185     public static String repeat(final char ch, final int repeat) {
6186         if (repeat <= 0) {
6187             return EMPTY;
6188         }
6189         final char[] buf = new char[repeat];
6190         Arrays.fill(buf, ch);
6191         return new String(buf);
6192     }
6193 
6194     /**
6195      * Repeat a String {@code repeat} times to form a
6196      * new String.
6197      *
6198      * <pre>
6199      * StringUtils.repeat(null, 2) = null
6200      * StringUtils.repeat("", 0)   = ""
6201      * StringUtils.repeat("", 2)   = ""
6202      * StringUtils.repeat("a", 3)  = "aaa"
6203      * StringUtils.repeat("ab", 2) = "abab"
6204      * StringUtils.repeat("a", -2) = ""
6205      * </pre>
6206      *
6207      * @param str  the String to repeat, may be null
6208      * @param repeat  number of times to repeat str, negative treated as zero
6209      * @return a new String consisting of the original String repeated,
6210      *  {@code null} if null String input
6211      */
6212     public static String repeat(final String str, final int repeat) {
6213         // Performance tuned for 2.0 (JDK1.4)
6214         if (str == null) {
6215             return null;
6216         }
6217         if (repeat <= 0) {
6218             return EMPTY;
6219         }
6220         final int inputLength = str.length();
6221         if (repeat == 1 || inputLength == 0) {
6222             return str;
6223         }
6224         if (inputLength == 1 && repeat <= PAD_LIMIT) {
6225             return repeat(str.charAt(0), repeat);
6226         }
6227 
6228         final int outputLength = inputLength * repeat;
6229         switch (inputLength) {
6230             case 1 :
6231                 return repeat(str.charAt(0), repeat);
6232             case 2 :
6233                 final char ch0 = str.charAt(0);
6234                 final char ch1 = str.charAt(1);
6235                 final char[] output2 = new char[outputLength];
6236                 for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6237                     output2[i] = ch0;
6238                     output2[i + 1] = ch1;
6239                 }
6240                 return new String(output2);
6241             default :
6242                 final StringBuilder buf = new StringBuilder(outputLength);
6243                 for (int i = 0; i < repeat; i++) {
6244                     buf.append(str);
6245                 }
6246                 return buf.toString();
6247         }
6248     }
6249 
6250     /**
6251      * Repeat a String {@code repeat} times to form a
6252      * new String, with a String separator injected each time.
6253      *
6254      * <pre>
6255      * StringUtils.repeat(null, null, 2) = null
6256      * StringUtils.repeat(null, "x", 2)  = null
6257      * StringUtils.repeat("", null, 0)   = ""
6258      * StringUtils.repeat("", "", 2)     = ""
6259      * StringUtils.repeat("", "x", 3)    = "xx"
6260      * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
6261      * </pre>
6262      *
6263      * @param str        the String to repeat, may be null
6264      * @param separator  the String to inject, may be null
6265      * @param repeat     number of times to repeat str, negative treated as zero
6266      * @return a new String consisting of the original String repeated,
6267      *  {@code null} if null String input
6268      * @since 2.5
6269      */
6270     public static String repeat(final String str, final String separator, final int repeat) {
6271         if (str == null || separator == null) {
6272             return repeat(str, repeat);
6273         }
6274         // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6275         final String result = repeat(str + separator, repeat);
6276         return removeEnd(result, separator);
6277     }
6278 
6279     /**
6280      * Replaces all occurrences of a String within another String.
6281      *
6282      * <p>A {@code null} reference passed to this method is a no-op.</p>
6283      *
6284      * <pre>
6285      * StringUtils.replace(null, *, *)        = null
6286      * StringUtils.replace("", *, *)          = ""
6287      * StringUtils.replace("any", null, *)    = "any"
6288      * StringUtils.replace("any", *, null)    = "any"
6289      * StringUtils.replace("any", "", *)      = "any"
6290      * StringUtils.replace("aba", "a", null)  = "aba"
6291      * StringUtils.replace("aba", "a", "")    = "b"
6292      * StringUtils.replace("aba", "a", "z")   = "zbz"
6293      * </pre>
6294      *
6295      * @see #replace(String text, String searchString, String replacement, int max)
6296      * @param text  text to search and replace in, may be null
6297      * @param searchString  the String to search for, may be null
6298      * @param replacement  the String to replace it with, may be null
6299      * @return the text with any replacements processed,
6300      *  {@code null} if null String input
6301      */
6302     public static String replace(final String text, final String searchString, final String replacement) {
6303         return replace(text, searchString, replacement, -1);
6304     }
6305 
6306     /**
6307      * Replaces a String with another String inside a larger String,
6308      * for the first {@code max} values of the search String.
6309      *
6310      * <p>A {@code null} reference passed to this method is a no-op.</p>
6311      *
6312      * <pre>
6313      * StringUtils.replace(null, *, *, *)         = null
6314      * StringUtils.replace("", *, *, *)           = ""
6315      * StringUtils.replace("any", null, *, *)     = "any"
6316      * StringUtils.replace("any", *, null, *)     = "any"
6317      * StringUtils.replace("any", "", *, *)       = "any"
6318      * StringUtils.replace("any", *, *, 0)        = "any"
6319      * StringUtils.replace("abaa", "a", null, -1) = "abaa"
6320      * StringUtils.replace("abaa", "a", "", -1)   = "b"
6321      * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
6322      * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
6323      * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
6324      * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
6325      * </pre>
6326      *
6327      * @param text  text to search and replace in, may be null
6328      * @param searchString  the String to search for, may be null
6329      * @param replacement  the String to replace it with, may be null
6330      * @param max  maximum number of values to replace, or {@code -1} if no maximum
6331      * @return the text with any replacements processed,
6332      *  {@code null} if null String input
6333      */
6334     public static String replace(final String text, final String searchString, final String replacement, final int max) {
6335         return replace(text, searchString, replacement, max, false);
6336     }
6337 
6338     /**
6339      * Replaces a String with another String inside a larger String,
6340      * for the first {@code max} values of the search String,
6341      * case-sensitively/insensitively based on {@code ignoreCase} value.
6342      *
6343      * <p>A {@code null} reference passed to this method is a no-op.</p>
6344      *
6345      * <pre>
6346      * StringUtils.replace(null, *, *, *, false)         = null
6347      * StringUtils.replace("", *, *, *, false)           = ""
6348      * StringUtils.replace("any", null, *, *, false)     = "any"
6349      * StringUtils.replace("any", *, null, *, false)     = "any"
6350      * StringUtils.replace("any", "", *, *, false)       = "any"
6351      * StringUtils.replace("any", *, *, 0, false)        = "any"
6352      * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
6353      * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
6354      * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
6355      * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
6356      * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
6357      * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
6358      * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
6359      * </pre>
6360      *
6361      * @param text  text to search and replace in, may be null
6362      * @param searchString  the String to search for (case-insensitive), may be null
6363      * @param replacement  the String to replace it with, may be null
6364      * @param max  maximum number of values to replace, or {@code -1} if no maximum
6365      * @param ignoreCase if true replace is case-insensitive, otherwise case-sensitive
6366      * @return the text with any replacements processed,
6367      *  {@code null} if null String input
6368      */
6369      private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
6370          if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
6371              return text;
6372          }
6373          if (ignoreCase) {
6374              searchString = searchString.toLowerCase();
6375          }
6376          int start = 0;
6377          int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6378          if (end == INDEX_NOT_FOUND) {
6379              return text;
6380          }
6381          final int replLength = searchString.length();
6382          int increase = Math.max(replacement.length() - replLength, 0);
6383          increase *= max < 0 ? 16 : Math.min(max, 64);
6384          final StringBuilder buf = new StringBuilder(text.length() + increase);
6385          while (end != INDEX_NOT_FOUND) {
6386              buf.append(text, start, end).append(replacement);
6387              start = end + replLength;
6388              if (--max == 0) {
6389                  break;
6390              }
6391              end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start);
6392          }
6393          buf.append(text, start, text.length());
6394          return buf.toString();
6395      }
6396 
6397     /**
6398      * Replaces each substring of the text String that matches the given regular expression
6399      * with the given replacement.
6400      *
6401      * This method is a {@code null} safe equivalent to:
6402      * <ul>
6403      *  <li>{@code text.replaceAll(regex, replacement)}</li>
6404      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
6405      * </ul>
6406      *
6407      * <p>A {@code null} reference passed to this method is a no-op.</p>
6408      *
6409      * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
6410      * is NOT automatically added.
6411      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6412      * DOTALL is also known as single-line mode in Perl.</p>
6413      *
6414      * <pre>
6415      * StringUtils.replaceAll(null, *, *)       = null
6416      * StringUtils.replaceAll("any", (String) null, *)   = "any"
6417      * StringUtils.replaceAll("any", *, null)   = "any"
6418      * StringUtils.replaceAll("", "", "zzz")    = "zzz"
6419      * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
6420      * StringUtils.replaceAll("", ".+", "zzz")  = ""
6421      * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
6422      * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\nz"
6423      * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
6424      * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
6425      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6426      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6427      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6428      * </pre>
6429      *
6430      * @param text  text to search and replace in, may be null
6431      * @param regex  the regular expression to which this string is to be matched
6432      * @param replacement  the string to be substituted for each match
6433      * @return  the text with any replacements processed,
6434      *              {@code null} if null String input
6435      *
6436      * @throws  java.util.regex.PatternSyntaxException
6437      *              if the regular expression's syntax is invalid
6438      *
6439      * @see #replacePattern(String, String, String)
6440      * @see String#replaceAll(String, String)
6441      * @see java.util.regex.Pattern
6442      * @see java.util.regex.Pattern#DOTALL
6443      * @since 3.5
6444      *
6445      * @deprecated Moved to RegExUtils.
6446      */
6447     @Deprecated
6448     public static String replaceAll(final String text, final String regex, final String replacement) {
6449         return RegExUtils.replaceAll(text, regex, replacement);
6450     }
6451 
6452     /**
6453      * Replaces all occurrences of a character in a String with another.
6454      * This is a null-safe version of {@link String#replace(char, char)}.
6455      *
6456      * <p>A {@code null} string input returns {@code null}.
6457      * An empty ("") string input returns an empty string.</p>
6458      *
6459      * <pre>
6460      * StringUtils.replaceChars(null, *, *)        = null
6461      * StringUtils.replaceChars("", *, *)          = ""
6462      * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
6463      * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
6464      * </pre>
6465      *
6466      * @param str  String to replace characters in, may be null
6467      * @param searchChar  the character to search for, may be null
6468      * @param replaceChar  the character to replace, may be null
6469      * @return modified String, {@code null} if null string input
6470      * @since 2.0
6471      */
6472     public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
6473         if (str == null) {
6474             return null;
6475         }
6476         return str.replace(searchChar, replaceChar);
6477     }
6478 
6479     /**
6480      * Replaces multiple characters in a String in one go.
6481      * This method can also be used to delete characters.
6482      *
6483      * <p>For example:<br>
6484      * {@code replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly}.</p>
6485      *
6486      * <p>A {@code null} string input returns {@code null}.
6487      * An empty ("") string input returns an empty string.
6488      * A null or empty set of search characters returns the input string.</p>
6489      *
6490      * <p>The length of the search characters should normally equal the length
6491      * of the replace characters.
6492      * If the search characters is longer, then the extra search characters
6493      * are deleted.
6494      * If the search characters is shorter, then the extra replace characters
6495      * are ignored.</p>
6496      *
6497      * <pre>
6498      * StringUtils.replaceChars(null, *, *)           = null
6499      * StringUtils.replaceChars("", *, *)             = ""
6500      * StringUtils.replaceChars("abc", null, *)       = "abc"
6501      * StringUtils.replaceChars("abc", "", *)         = "abc"
6502      * StringUtils.replaceChars("abc", "b", null)     = "ac"
6503      * StringUtils.replaceChars("abc", "b", "")       = "ac"
6504      * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
6505      * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
6506      * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
6507      * </pre>
6508      *
6509      * @param str  String to replace characters in, may be null
6510      * @param searchChars  a set of characters to search for, may be null
6511      * @param replaceChars  a set of characters to replace, may be null
6512      * @return modified String, {@code null} if null string input
6513      * @since 2.0
6514      */
6515     public static String replaceChars(final String str, final String searchChars, String replaceChars) {
6516         if (isEmpty(str) || isEmpty(searchChars)) {
6517             return str;
6518         }
6519         if (replaceChars == null) {
6520             replaceChars = EMPTY;
6521         }
6522         boolean modified = false;
6523         final int replaceCharsLength = replaceChars.length();
6524         final int strLength = str.length();
6525         final StringBuilder buf = new StringBuilder(strLength);
6526         for (int i = 0; i < strLength; i++) {
6527             final char ch = str.charAt(i);
6528             final int index = searchChars.indexOf(ch);
6529             if (index >= 0) {
6530                 modified = true;
6531                 if (index < replaceCharsLength) {
6532                     buf.append(replaceChars.charAt(index));
6533                 }
6534             } else {
6535                 buf.append(ch);
6536             }
6537         }
6538         if (modified) {
6539             return buf.toString();
6540         }
6541         return str;
6542     }
6543 
6544     /**
6545      * Replaces all occurrences of Strings within another String.
6546      *
6547      * <p>
6548      * A {@code null} reference passed to this method is a no-op, or if
6549      * any "search string" or "string to replace" is null, that replace will be
6550      * ignored. This will not repeat. For repeating replaces, call the
6551      * overloaded method.
6552      * </p>
6553      *
6554      * <pre>
6555      *  StringUtils.replaceEach(null, *, *)        = null
6556      *  StringUtils.replaceEach("", *, *)          = ""
6557      *  StringUtils.replaceEach("aba", null, null) = "aba"
6558      *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
6559      *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
6560      *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
6561      *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
6562      *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
6563      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
6564      *  (example of how it does not repeat)
6565      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
6566      * </pre>
6567      *
6568      * @param text
6569      *            text to search and replace in, no-op if null
6570      * @param searchList
6571      *            the Strings to search for, no-op if null
6572      * @param replacementList
6573      *            the Strings to replace them with, no-op if null
6574      * @return the text with any replacements processed, {@code null} if
6575      *         null String input
6576      * @throws IllegalArgumentException
6577      *             if the lengths of the arrays are not the same (null is ok,
6578      *             and/or size 0)
6579      * @since 2.4
6580      */
6581     public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
6582         return replaceEach(text, searchList, replacementList, false, 0);
6583     }
6584 
6585     /**
6586      * Replace all occurrences of Strings within another String.
6587      * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
6588      * {@link #replaceEach(String, String[], String[])}
6589      *
6590      * <p>
6591      * A {@code null} reference passed to this method is a no-op, or if
6592      * any "search string" or "string to replace" is null, that replace will be
6593      * ignored.
6594      * </p>
6595      *
6596      * <pre>
6597      *  StringUtils.replaceEach(null, *, *, *, *) = null
6598      *  StringUtils.replaceEach("", *, *, *, *) = ""
6599      *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
6600      *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
6601      *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
6602      *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
6603      *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
6604      *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
6605      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
6606      *  (example of how it repeats)
6607      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
6608      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
6609      *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
6610      * </pre>
6611      *
6612      * @param text
6613      *            text to search and replace in, no-op if null
6614      * @param searchList
6615      *            the Strings to search for, no-op if null
6616      * @param replacementList
6617      *            the Strings to replace them with, no-op if null
6618      * @param repeat if true, then replace repeatedly
6619      *       until there are no more possible replacements or timeToLive < 0
6620      * @param timeToLive
6621      *            if less than 0 then there is a circular reference and endless
6622      *            loop
6623      * @return the text with any replacements processed, {@code null} if
6624      *         null String input
6625      * @throws IllegalStateException
6626      *             if the search is repeating and there is an endless loop due
6627      *             to outputs of one being inputs to another
6628      * @throws IllegalArgumentException
6629      *             if the lengths of the arrays are not the same (null is ok,
6630      *             and/or size 0)
6631      * @since 2.4
6632      */
6633     private static String replaceEach(
6634             final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
6635 
6636         // mchyzer Performance note: This creates very few new objects (one major goal)
6637         // let me know if there are performance requests, we can create a harness to measure
6638 
6639         // if recursing, this shouldn't be less than 0
6640         if (timeToLive < 0) {
6641             final Set<String> searchSet = new HashSet<>(Arrays.asList(searchList));
6642             final Set<String> replacementSet = new HashSet<>(Arrays.asList(replacementList));
6643             searchSet.retainAll(replacementSet);
6644             if (!searchSet.isEmpty()) {
6645                 throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
6646                         "output of one loop is the input of another");
6647             }
6648         }
6649 
6650         if (isEmpty(text) || ArrayUtils.isEmpty(searchList) || ArrayUtils.isEmpty(replacementList) || ArrayUtils.isNotEmpty(searchList) && timeToLive == -1) {
6651             return text;
6652         }
6653 
6654         final int searchLength = searchList.length;
6655         final int replacementLength = replacementList.length;
6656 
6657         // make sure lengths are ok, these need to be equal
6658         if (searchLength != replacementLength) {
6659             throw new IllegalArgumentException("Search and Replace array lengths don't match: "
6660                 + searchLength
6661                 + " vs "
6662                 + replacementLength);
6663         }
6664 
6665         // keep track of which still have matches
6666         final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
6667 
6668         // index on index that the match was found
6669         int textIndex = -1;
6670         int replaceIndex = -1;
6671         int tempIndex;
6672 
6673         // index of replace array that will replace the search string found
6674         // NOTE: logic duplicated below START
6675         for (int i = 0; i < searchLength; i++) {
6676             if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6677                 continue;
6678             }
6679             tempIndex = text.indexOf(searchList[i]);
6680 
6681             // see if we need to keep searching for this
6682             if (tempIndex == -1) {
6683                 noMoreMatchesForReplIndex[i] = true;
6684             } else if (textIndex == -1 || tempIndex < textIndex) {
6685                 textIndex = tempIndex;
6686                 replaceIndex = i;
6687             }
6688         }
6689         // NOTE: logic mostly below END
6690 
6691         // no search strings found, we are done
6692         if (textIndex == -1) {
6693             return text;
6694         }
6695 
6696         int start = 0;
6697 
6698         // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
6699         int increase = 0;
6700 
6701         // count the replacement text elements that are larger than their corresponding text being replaced
6702         for (int i = 0; i < searchList.length; i++) {
6703             if (searchList[i] == null || replacementList[i] == null) {
6704                 continue;
6705             }
6706             final int greater = replacementList[i].length() - searchList[i].length();
6707             if (greater > 0) {
6708                 increase += 3 * greater; // assume 3 matches
6709             }
6710         }
6711         // have upper-bound at 20% increase, then let Java take over
6712         increase = Math.min(increase, text.length() / 5);
6713 
6714         final StringBuilder buf = new StringBuilder(text.length() + increase);
6715 
6716         while (textIndex != -1) {
6717 
6718             for (int i = start; i < textIndex; i++) {
6719                 buf.append(text.charAt(i));
6720             }
6721             buf.append(replacementList[replaceIndex]);
6722 
6723             start = textIndex + searchList[replaceIndex].length();
6724 
6725             textIndex = -1;
6726             replaceIndex = -1;
6727             // find the next earliest match
6728             // NOTE: logic mostly duplicated above START
6729             for (int i = 0; i < searchLength; i++) {
6730                 if (noMoreMatchesForReplIndex[i] || isEmpty(searchList[i]) || replacementList[i] == null) {
6731                     continue;
6732                 }
6733                 tempIndex = text.indexOf(searchList[i], start);
6734 
6735                 // see if we need to keep searching for this
6736                 if (tempIndex == -1) {
6737                     noMoreMatchesForReplIndex[i] = true;
6738                 } else if (textIndex == -1 || tempIndex < textIndex) {
6739                     textIndex = tempIndex;
6740                     replaceIndex = i;
6741                 }
6742             }
6743             // NOTE: logic duplicated above END
6744 
6745         }
6746         final int textLength = text.length();
6747         for (int i = start; i < textLength; i++) {
6748             buf.append(text.charAt(i));
6749         }
6750         final String result = buf.toString();
6751         if (!repeat) {
6752             return result;
6753         }
6754 
6755         return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
6756     }
6757 
6758     /**
6759      * Replaces all occurrences of Strings within another String.
6760      *
6761      * <p>
6762      * A {@code null} reference passed to this method is a no-op, or if
6763      * any "search string" or "string to replace" is null, that replace will be
6764      * ignored.
6765      * </p>
6766      *
6767      * <pre>
6768      *  StringUtils.replaceEachRepeatedly(null, *, *) = null
6769      *  StringUtils.replaceEachRepeatedly("", *, *) = ""
6770      *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
6771      *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
6772      *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
6773      *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
6774      *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
6775      *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
6776      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
6777      *  (example of how it repeats)
6778      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
6779      *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
6780      * </pre>
6781      *
6782      * @param text
6783      *            text to search and replace in, no-op if null
6784      * @param searchList
6785      *            the Strings to search for, no-op if null
6786      * @param replacementList
6787      *            the Strings to replace them with, no-op if null
6788      * @return the text with any replacements processed, {@code null} if
6789      *         null String input
6790      * @throws IllegalStateException
6791      *             if the search is repeating and there is an endless loop due
6792      *             to outputs of one being inputs to another
6793      * @throws IllegalArgumentException
6794      *             if the lengths of the arrays are not the same (null is ok,
6795      *             and/or size 0)
6796      * @since 2.4
6797      */
6798     public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
6799         return replaceEach(text, searchList, replacementList, true, ArrayUtils.getLength(searchList));
6800     }
6801 
6802     /**
6803      * Replaces the first substring of the text string that matches the given regular expression
6804      * with the given replacement.
6805      *
6806      * This method is a {@code null} safe equivalent to:
6807      * <ul>
6808      *  <li>{@code text.replaceFirst(regex, replacement)}</li>
6809      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
6810      * </ul>
6811      *
6812      * <p>A {@code null} reference passed to this method is a no-op.</p>
6813      *
6814      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
6815      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
6816      * DOTALL is also known as single-line mode in Perl.</p>
6817      *
6818      * <pre>
6819      * StringUtils.replaceFirst(null, *, *)       = null
6820      * StringUtils.replaceFirst("any", (String) null, *)   = "any"
6821      * StringUtils.replaceFirst("any", *, null)   = "any"
6822      * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
6823      * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
6824      * StringUtils.replaceFirst("", ".+", "zzz")  = ""
6825      * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
6826      * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")      = "z\n&lt;__&gt;"
6827      * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z")  = "z"
6828      * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
6829      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
6830      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
6831      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
6832      * </pre>
6833      *
6834      * @param text  text to search and replace in, may be null
6835      * @param regex  the regular expression to which this string is to be matched
6836      * @param replacement  the string to be substituted for the first match
6837      * @return  the text with the first replacement processed,
6838      *              {@code null} if null String input
6839      *
6840      * @throws  java.util.regex.PatternSyntaxException
6841      *              if the regular expression's syntax is invalid
6842      *
6843      * @see String#replaceFirst(String, String)
6844      * @see java.util.regex.Pattern
6845      * @see java.util.regex.Pattern#DOTALL
6846      * @since 3.5
6847      *
6848      * @deprecated Moved to RegExUtils.
6849      */
6850     @Deprecated
6851     public static String replaceFirst(final String text, final String regex, final String replacement) {
6852         return RegExUtils.replaceFirst(text, regex, replacement);
6853     }
6854 
6855     /**
6856      * Case insensitively replaces all occurrences of a String within another String.
6857      *
6858      * <p>A {@code null} reference passed to this method is a no-op.</p>
6859      *
6860      * <pre>
6861      * StringUtils.replaceIgnoreCase(null, *, *)        = null
6862      * StringUtils.replaceIgnoreCase("", *, *)          = ""
6863      * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
6864      * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
6865      * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
6866      * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
6867      * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
6868      * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
6869      * </pre>
6870      *
6871      * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6872      * @param text  text to search and replace in, may be null
6873      * @param searchString  the String to search for (case-insensitive), may be null
6874      * @param replacement  the String to replace it with, may be null
6875      * @return the text with any replacements processed,
6876      *  {@code null} if null String input
6877      * @since 3.5
6878      */
6879      public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
6880          return replaceIgnoreCase(text, searchString, replacement, -1);
6881      }
6882 
6883     /**
6884      * Case insensitively replaces a String with another String inside a larger String,
6885      * for the first {@code max} values of the search String.
6886      *
6887      * <p>A {@code null} reference passed to this method is a no-op.</p>
6888      *
6889      * <pre>
6890      * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
6891      * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
6892      * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
6893      * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
6894      * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
6895      * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
6896      * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
6897      * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
6898      * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
6899      * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
6900      * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
6901      * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
6902      * </pre>
6903      *
6904      * @param text  text to search and replace in, may be null
6905      * @param searchString  the String to search for (case-insensitive), may be null
6906      * @param replacement  the String to replace it with, may be null
6907      * @param max  maximum number of values to replace, or {@code -1} if no maximum
6908      * @return the text with any replacements processed,
6909      *  {@code null} if null String input
6910      * @since 3.5
6911      */
6912     public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
6913         return replace(text, searchString, replacement, max, true);
6914     }
6915 
6916     /**
6917      * Replaces a String with another String inside a larger String, once.
6918      *
6919      * <p>A {@code null} reference passed to this method is a no-op.</p>
6920      *
6921      * <pre>
6922      * StringUtils.replaceOnce(null, *, *)        = null
6923      * StringUtils.replaceOnce("", *, *)          = ""
6924      * StringUtils.replaceOnce("any", null, *)    = "any"
6925      * StringUtils.replaceOnce("any", *, null)    = "any"
6926      * StringUtils.replaceOnce("any", "", *)      = "any"
6927      * StringUtils.replaceOnce("aba", "a", null)  = "aba"
6928      * StringUtils.replaceOnce("aba", "a", "")    = "ba"
6929      * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
6930      * </pre>
6931      *
6932      * @see #replace(String text, String searchString, String replacement, int max)
6933      * @param text  text to search and replace in, may be null
6934      * @param searchString  the String to search for, may be null
6935      * @param replacement  the String to replace with, may be null
6936      * @return the text with any replacements processed,
6937      *  {@code null} if null String input
6938      */
6939     public static String replaceOnce(final String text, final String searchString, final String replacement) {
6940         return replace(text, searchString, replacement, 1);
6941     }
6942 
6943     /**
6944      * Case insensitively replaces a String with another String inside a larger String, once.
6945      *
6946      * <p>A {@code null} reference passed to this method is a no-op.</p>
6947      *
6948      * <pre>
6949      * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
6950      * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
6951      * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
6952      * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
6953      * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
6954      * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
6955      * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
6956      * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
6957      * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
6958      * </pre>
6959      *
6960      * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
6961      * @param text  text to search and replace in, may be null
6962      * @param searchString  the String to search for (case-insensitive), may be null
6963      * @param replacement  the String to replace with, may be null
6964      * @return the text with any replacements processed,
6965      *  {@code null} if null String input
6966      * @since 3.5
6967      */
6968     public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
6969         return replaceIgnoreCase(text, searchString, replacement, 1);
6970     }
6971 
6972     /**
6973      * Replaces each substring of the source String that matches the given regular expression with the given
6974      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
6975      *
6976      * This call is a {@code null} safe equivalent to:
6977      * <ul>
6978      * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
6979      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
6980      * </ul>
6981      *
6982      * <p>A {@code null} reference passed to this method is a no-op.</p>
6983      *
6984      * <pre>
6985      * StringUtils.replacePattern(null, *, *)       = null
6986      * StringUtils.replacePattern("any", (String) null, *)   = "any"
6987      * StringUtils.replacePattern("any", *, null)   = "any"
6988      * StringUtils.replacePattern("", "", "zzz")    = "zzz"
6989      * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
6990      * StringUtils.replacePattern("", ".+", "zzz")  = ""
6991      * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z")       = "z"
6992      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
6993      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
6994      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
6995      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
6996      * </pre>
6997      *
6998      * @param source
6999      *            the source string
7000      * @param regex
7001      *            the regular expression to which this string is to be matched
7002      * @param replacement
7003      *            the string to be substituted for each match
7004      * @return The resulting {@link String}
7005      * @see #replaceAll(String, String, String)
7006      * @see String#replaceAll(String, String)
7007      * @see Pattern#DOTALL
7008      * @since 3.2
7009      * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
7010      *
7011      * @deprecated Moved to RegExUtils.
7012      */
7013     @Deprecated
7014     public static String replacePattern(final String source, final String regex, final String replacement) {
7015         return RegExUtils.replacePattern(source, regex, replacement);
7016     }
7017 
7018     /**
7019      * Reverses a String as per {@link StringBuilder#reverse()}.
7020      *
7021      * <p>A {@code null} String returns {@code null}.</p>
7022      *
7023      * <pre>
7024      * StringUtils.reverse(null)  = null
7025      * StringUtils.reverse("")    = ""
7026      * StringUtils.reverse("bat") = "tab"
7027      * </pre>
7028      *
7029      * @param str  the String to reverse, may be null
7030      * @return the reversed String, {@code null} if null String input
7031      */
7032     public static String reverse(final String str) {
7033         if (str == null) {
7034             return null;
7035         }
7036         return new StringBuilder(str).reverse().toString();
7037     }
7038 
7039     /**
7040      * Reverses a String that is delimited by a specific character.
7041      *
7042      * <p>The Strings between the delimiters are not reversed.
7043      * Thus java.lang.String becomes String.lang.java (if the delimiter
7044      * is {@code '.'}).</p>
7045      *
7046      * <pre>
7047      * StringUtils.reverseDelimited(null, *)      = null
7048      * StringUtils.reverseDelimited("", *)        = ""
7049      * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7050      * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7051      * </pre>
7052      *
7053      * @param str  the String to reverse, may be null
7054      * @param separatorChar  the separator character to use
7055      * @return the reversed String, {@code null} if null String input
7056      * @since 2.0
7057      */
7058     public static String reverseDelimited(final String str, final char separatorChar) {
7059         if (str == null) {
7060             return null;
7061         }
7062         // could implement manually, but simple way is to reuse other,
7063         // probably slower, methods.
7064         final String[] strs = split(str, separatorChar);
7065         ArrayUtils.reverse(strs);
7066         return join(strs, separatorChar);
7067     }
7068 
7069     /**
7070      * Gets the rightmost {@code len} characters of a String.
7071      *
7072      * <p>If {@code len} characters are not available, or the String
7073      * is {@code null}, the String will be returned without an
7074      * an exception. An empty String is returned if len is negative.</p>
7075      *
7076      * <pre>
7077      * StringUtils.right(null, *)    = null
7078      * StringUtils.right(*, -ve)     = ""
7079      * StringUtils.right("", *)      = ""
7080      * StringUtils.right("abc", 0)   = ""
7081      * StringUtils.right("abc", 2)   = "bc"
7082      * StringUtils.right("abc", 4)   = "abc"
7083      * </pre>
7084      *
7085      * @param str  the String to get the rightmost characters from, may be null
7086      * @param len  the length of the required String
7087      * @return the rightmost characters, {@code null} if null String input
7088      */
7089     public static String right(final String str, final int len) {
7090         if (str == null) {
7091             return null;
7092         }
7093         if (len < 0) {
7094             return EMPTY;
7095         }
7096         if (str.length() <= len) {
7097             return str;
7098         }
7099         return str.substring(str.length() - len);
7100     }
7101 
7102     /**
7103      * Right pad a String with spaces (' ').
7104      *
7105      * <p>The String is padded to the size of {@code size}.</p>
7106      *
7107      * <pre>
7108      * StringUtils.rightPad(null, *)   = null
7109      * StringUtils.rightPad("", 3)     = "   "
7110      * StringUtils.rightPad("bat", 3)  = "bat"
7111      * StringUtils.rightPad("bat", 5)  = "bat  "
7112      * StringUtils.rightPad("bat", 1)  = "bat"
7113      * StringUtils.rightPad("bat", -1) = "bat"
7114      * </pre>
7115      *
7116      * @param str  the String to pad out, may be null
7117      * @param size  the size to pad to
7118      * @return right padded String or original String if no padding is necessary,
7119      *  {@code null} if null String input
7120      */
7121     public static String rightPad(final String str, final int size) {
7122         return rightPad(str, size, ' ');
7123     }
7124 
7125     /**
7126      * Right pad a String with a specified character.
7127      *
7128      * <p>The String is padded to the size of {@code size}.</p>
7129      *
7130      * <pre>
7131      * StringUtils.rightPad(null, *, *)     = null
7132      * StringUtils.rightPad("", 3, 'z')     = "zzz"
7133      * StringUtils.rightPad("bat", 3, 'z')  = "bat"
7134      * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
7135      * StringUtils.rightPad("bat", 1, 'z')  = "bat"
7136      * StringUtils.rightPad("bat", -1, 'z') = "bat"
7137      * </pre>
7138      *
7139      * @param str  the String to pad out, may be null
7140      * @param size  the size to pad to
7141      * @param padChar  the character to pad with
7142      * @return right padded String or original String if no padding is necessary,
7143      *  {@code null} if null String input
7144      * @since 2.0
7145      */
7146     public static String rightPad(final String str, final int size, final char padChar) {
7147         if (str == null) {
7148             return null;
7149         }
7150         final int pads = size - str.length();
7151         if (pads <= 0) {
7152             return str; // returns original String when possible
7153         }
7154         if (pads > PAD_LIMIT) {
7155             return rightPad(str, size, String.valueOf(padChar));
7156         }
7157         return str.concat(repeat(padChar, pads));
7158     }
7159 
7160     /**
7161      * Right pad a String with a specified String.
7162      *
7163      * <p>The String is padded to the size of {@code size}.</p>
7164      *
7165      * <pre>
7166      * StringUtils.rightPad(null, *, *)      = null
7167      * StringUtils.rightPad("", 3, "z")      = "zzz"
7168      * StringUtils.rightPad("bat", 3, "yz")  = "bat"
7169      * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
7170      * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
7171      * StringUtils.rightPad("bat", 1, "yz")  = "bat"
7172      * StringUtils.rightPad("bat", -1, "yz") = "bat"
7173      * StringUtils.rightPad("bat", 5, null)  = "bat  "
7174      * StringUtils.rightPad("bat", 5, "")    = "bat  "
7175      * </pre>
7176      *
7177      * @param str  the String to pad out, may be null
7178      * @param size  the size to pad to
7179      * @param padStr  the String to pad with, null or empty treated as single space
7180      * @return right padded String or original String if no padding is necessary,
7181      *  {@code null} if null String input
7182      */
7183     public static String rightPad(final String str, final int size, String padStr) {
7184         if (str == null) {
7185             return null;
7186         }
7187         if (isEmpty(padStr)) {
7188             padStr = SPACE;
7189         }
7190         final int padLen = padStr.length();
7191         final int strLen = str.length();
7192         final int pads = size - strLen;
7193         if (pads <= 0) {
7194             return str; // returns original String when possible
7195         }
7196         if (padLen == 1 && pads <= PAD_LIMIT) {
7197             return rightPad(str, size, padStr.charAt(0));
7198         }
7199 
7200         if (pads == padLen) {
7201             return str.concat(padStr);
7202         }
7203         if (pads < padLen) {
7204             return str.concat(padStr.substring(0, pads));
7205         }
7206         final char[] padding = new char[pads];
7207         final char[] padChars = padStr.toCharArray();
7208         for (int i = 0; i < pads; i++) {
7209             padding[i] = padChars[i % padLen];
7210         }
7211         return str.concat(new String(padding));
7212     }
7213 
7214     /**
7215      * Rotate (circular shift) a String of {@code shift} characters.
7216      * <ul>
7217      *  <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7218      *  <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7219      * </ul>
7220      *
7221      * <pre>
7222      * StringUtils.rotate(null, *)        = null
7223      * StringUtils.rotate("", *)          = ""
7224      * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
7225      * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
7226      * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
7227      * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
7228      * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
7229      * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
7230      * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
7231      * </pre>
7232      *
7233      * @param str  the String to rotate, may be null
7234      * @param shift  number of time to shift (positive : right shift, negative : left shift)
7235      * @return the rotated String,
7236      *          or the original String if {@code shift == 0},
7237      *          or {@code null} if null String input
7238      * @since 3.5
7239      */
7240     public static String rotate(final String str, final int shift) {
7241         if (str == null) {
7242             return null;
7243         }
7244 
7245         final int strLen = str.length();
7246         if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7247             return str;
7248         }
7249 
7250         final StringBuilder builder = new StringBuilder(strLen);
7251         final int offset = - (shift % strLen);
7252         builder.append(substring(str, offset));
7253         builder.append(substring(str, 0, offset));
7254         return builder.toString();
7255     }
7256 
7257     /**
7258      * Splits the provided text into an array, using whitespace as the
7259      * separator.
7260      * Whitespace is defined by {@link Character#isWhitespace(char)}.
7261      *
7262      * <p>The separator is not included in the returned String array.
7263      * Adjacent separators are treated as one separator.
7264      * For more control over the split use the StrTokenizer class.</p>
7265      *
7266      * <p>A {@code null} input String returns {@code null}.</p>
7267      *
7268      * <pre>
7269      * StringUtils.split(null)       = null
7270      * StringUtils.split("")         = []
7271      * StringUtils.split("abc def")  = ["abc", "def"]
7272      * StringUtils.split("abc  def") = ["abc", "def"]
7273      * StringUtils.split(" abc ")    = ["abc"]
7274      * </pre>
7275      *
7276      * @param str  the String to parse, may be null
7277      * @return an array of parsed Strings, {@code null} if null String input
7278      */
7279     public static String[] split(final String str) {
7280         return split(str, null, -1);
7281     }
7282 
7283     /**
7284      * Splits the provided text into an array, separator specified.
7285      * This is an alternative to using StringTokenizer.
7286      *
7287      * <p>The separator is not included in the returned String array.
7288      * Adjacent separators are treated as one separator.
7289      * For more control over the split use the StrTokenizer class.</p>
7290      *
7291      * <p>A {@code null} input String returns {@code null}.</p>
7292      *
7293      * <pre>
7294      * StringUtils.split(null, *)         = null
7295      * StringUtils.split("", *)           = []
7296      * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
7297      * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
7298      * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
7299      * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
7300      * </pre>
7301      *
7302      * @param str  the String to parse, may be null
7303      * @param separatorChar  the character used as the delimiter
7304      * @return an array of parsed Strings, {@code null} if null String input
7305      * @since 2.0
7306      */
7307     public static String[] split(final String str, final char separatorChar) {
7308         return splitWorker(str, separatorChar, false);
7309     }
7310 
7311     /**
7312      * Splits the provided text into an array, separators specified.
7313      * This is an alternative to using StringTokenizer.
7314      *
7315      * <p>The separator is not included in the returned String array.
7316      * Adjacent separators are treated as one separator.
7317      * For more control over the split use the StrTokenizer class.</p>
7318      *
7319      * <p>A {@code null} input String returns {@code null}.
7320      * A {@code null} separatorChars splits on whitespace.</p>
7321      *
7322      * <pre>
7323      * StringUtils.split(null, *)         = null
7324      * StringUtils.split("", *)           = []
7325      * StringUtils.split("abc def", null) = ["abc", "def"]
7326      * StringUtils.split("abc def", " ")  = ["abc", "def"]
7327      * StringUtils.split("abc  def", " ") = ["abc", "def"]
7328      * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
7329      * </pre>
7330      *
7331      * @param str  the String to parse, may be null
7332      * @param separatorChars  the characters used as the delimiters,
7333      *  {@code null} splits on whitespace
7334      * @return an array of parsed Strings, {@code null} if null String input
7335      */
7336     public static String[] split(final String str, final String separatorChars) {
7337         return splitWorker(str, separatorChars, -1, false);
7338     }
7339 
7340     /**
7341      * Splits the provided text into an array with a maximum length,
7342      * separators specified.
7343      *
7344      * <p>The separator is not included in the returned String array.
7345      * Adjacent separators are treated as one separator.</p>
7346      *
7347      * <p>A {@code null} input String returns {@code null}.
7348      * A {@code null} separatorChars splits on whitespace.</p>
7349      *
7350      * <p>If more than {@code max} delimited substrings are found, the last
7351      * returned string includes all characters after the first {@code max - 1}
7352      * returned strings (including separator characters).</p>
7353      *
7354      * <pre>
7355      * StringUtils.split(null, *, *)            = null
7356      * StringUtils.split("", *, *)              = []
7357      * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
7358      * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
7359      * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7360      * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7361      * </pre>
7362      *
7363      * @param str  the String to parse, may be null
7364      * @param separatorChars  the characters used as the delimiters,
7365      *  {@code null} splits on whitespace
7366      * @param max  the maximum number of elements to include in the
7367      *  array. A zero or negative value implies no limit
7368      * @return an array of parsed Strings, {@code null} if null String input
7369      */
7370     public static String[] split(final String str, final String separatorChars, final int max) {
7371         return splitWorker(str, separatorChars, max, false);
7372     }
7373 
7374     /**
7375      * Splits a String by Character type as returned by
7376      * {@code java.lang.Character.getType(char)}. Groups of contiguous
7377      * characters of the same type are returned as complete tokens.
7378      * <pre>
7379      * StringUtils.splitByCharacterType(null)         = null
7380      * StringUtils.splitByCharacterType("")           = []
7381      * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7382      * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7383      * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7384      * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
7385      * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
7386      * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
7387      * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
7388      * </pre>
7389      * @param str the String to split, may be {@code null}
7390      * @return an array of parsed Strings, {@code null} if null String input
7391      * @since 2.4
7392      */
7393     public static String[] splitByCharacterType(final String str) {
7394         return splitByCharacterType(str, false);
7395     }
7396 
7397     /**
7398      * <p>Splits a String by Character type as returned by
7399      * {@code java.lang.Character.getType(char)}. Groups of contiguous
7400      * characters of the same type are returned as complete tokens, with the
7401      * following exception: if {@code camelCase} is {@code true},
7402      * the character of type {@code Character.UPPERCASE_LETTER}, if any,
7403      * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
7404      * will belong to the following token rather than to the preceding, if any,
7405      * {@code Character.UPPERCASE_LETTER} token.
7406      * @param str the String to split, may be {@code null}
7407      * @param camelCase whether to use so-called "camel-case" for letter types
7408      * @return an array of parsed Strings, {@code null} if null String input
7409      * @since 2.4
7410      */
7411     private static String[] splitByCharacterType(final String str, final boolean camelCase) {
7412         if (str == null) {
7413             return null;
7414         }
7415         if (str.isEmpty()) {
7416             return ArrayUtils.EMPTY_STRING_ARRAY;
7417         }
7418         final char[] c = str.toCharArray();
7419         final List<String> list = new ArrayList<>();
7420         int tokenStart = 0;
7421         int currentType = Character.getType(c[tokenStart]);
7422         for (int pos = tokenStart + 1; pos < c.length; pos++) {
7423             final int type = Character.getType(c[pos]);
7424             if (type == currentType) {
7425                 continue;
7426             }
7427             if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
7428                 final int newTokenStart = pos - 1;
7429                 if (newTokenStart != tokenStart) {
7430                     list.add(new String(c, tokenStart, newTokenStart - tokenStart));
7431                     tokenStart = newTokenStart;
7432                 }
7433             } else {
7434                 list.add(new String(c, tokenStart, pos - tokenStart));
7435                 tokenStart = pos;
7436             }
7437             currentType = type;
7438         }
7439         list.add(new String(c, tokenStart, c.length - tokenStart));
7440         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7441     }
7442 
7443     /**
7444      * <p>Splits a String by Character type as returned by
7445      * {@code java.lang.Character.getType(char)}. Groups of contiguous
7446      * characters of the same type are returned as complete tokens, with the
7447      * following exception: the character of type
7448      * {@code Character.UPPERCASE_LETTER}, if any, immediately
7449      * preceding a token of type {@code Character.LOWERCASE_LETTER}
7450      * will belong to the following token rather than to the preceding, if any,
7451      * {@code Character.UPPERCASE_LETTER} token.
7452      * <pre>
7453      * StringUtils.splitByCharacterTypeCamelCase(null)         = null
7454      * StringUtils.splitByCharacterTypeCamelCase("")           = []
7455      * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
7456      * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
7457      * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
7458      * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
7459      * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
7460      * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
7461      * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
7462      * </pre>
7463      * @param str the String to split, may be {@code null}
7464      * @return an array of parsed Strings, {@code null} if null String input
7465      * @since 2.4
7466      */
7467     public static String[] splitByCharacterTypeCamelCase(final String str) {
7468         return splitByCharacterType(str, true);
7469     }
7470 
7471     /**
7472      * <p>Splits the provided text into an array, separator string specified.
7473      *
7474      * <p>The separator(s) will not be included in the returned String array.
7475      * Adjacent separators are treated as one separator.</p>
7476      *
7477      * <p>A {@code null} input String returns {@code null}.
7478      * A {@code null} separator splits on whitespace.</p>
7479      *
7480      * <pre>
7481      * StringUtils.splitByWholeSeparator(null, *)               = null
7482      * StringUtils.splitByWholeSeparator("", *)                 = []
7483      * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
7484      * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
7485      * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7486      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7487      * </pre>
7488      *
7489      * @param str  the String to parse, may be null
7490      * @param separator  String containing the String to be used as a delimiter,
7491      *  {@code null} splits on whitespace
7492      * @return an array of parsed Strings, {@code null} if null String was input
7493      */
7494     public static String[] splitByWholeSeparator(final String str, final String separator) {
7495         return splitByWholeSeparatorWorker(str, separator, -1, false);
7496     }
7497 
7498     /**
7499      * Splits the provided text into an array, separator string specified.
7500      * Returns a maximum of {@code max} substrings.
7501      *
7502      * <p>The separator(s) will not be included in the returned String array.
7503      * Adjacent separators are treated as one separator.</p>
7504      *
7505      * <p>A {@code null} input String returns {@code null}.
7506      * A {@code null} separator splits on whitespace.</p>
7507      *
7508      * <pre>
7509      * StringUtils.splitByWholeSeparator(null, *, *)               = null
7510      * StringUtils.splitByWholeSeparator("", *, *)                 = []
7511      * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
7512      * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
7513      * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7514      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7515      * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7516      * </pre>
7517      *
7518      * @param str  the String to parse, may be null
7519      * @param separator  String containing the String to be used as a delimiter,
7520      *  {@code null} splits on whitespace
7521      * @param max  the maximum number of elements to include in the returned
7522      *  array. A zero or negative value implies no limit.
7523      * @return an array of parsed Strings, {@code null} if null String was input
7524      */
7525     public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
7526         return splitByWholeSeparatorWorker(str, separator, max, false);
7527     }
7528 
7529     /**
7530      * Splits the provided text into an array, separator string specified.
7531      *
7532      * <p>The separator is not included in the returned String array.
7533      * Adjacent separators are treated as separators for empty tokens.
7534      * For more control over the split use the StrTokenizer class.</p>
7535      *
7536      * <p>A {@code null} input String returns {@code null}.
7537      * A {@code null} separator splits on whitespace.</p>
7538      *
7539      * <pre>
7540      * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
7541      * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
7542      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
7543      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
7544      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
7545      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
7546      * </pre>
7547      *
7548      * @param str  the String to parse, may be null
7549      * @param separator  String containing the String to be used as a delimiter,
7550      *  {@code null} splits on whitespace
7551      * @return an array of parsed Strings, {@code null} if null String was input
7552      * @since 2.4
7553      */
7554     public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
7555         return splitByWholeSeparatorWorker(str, separator, -1, true);
7556     }
7557 
7558     /**
7559      * Splits the provided text into an array, separator string specified.
7560      * Returns a maximum of {@code max} substrings.
7561      *
7562      * <p>The separator is not included in the returned String array.
7563      * Adjacent separators are treated as separators for empty tokens.
7564      * For more control over the split use the StrTokenizer class.</p>
7565      *
7566      * <p>A {@code null} input String returns {@code null}.
7567      * A {@code null} separator splits on whitespace.</p>
7568      *
7569      * <pre>
7570      * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
7571      * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
7572      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
7573      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
7574      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
7575      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
7576      * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
7577      * </pre>
7578      *
7579      * @param str  the String to parse, may be null
7580      * @param separator  String containing the String to be used as a delimiter,
7581      *  {@code null} splits on whitespace
7582      * @param max  the maximum number of elements to include in the returned
7583      *  array. A zero or negative value implies no limit.
7584      * @return an array of parsed Strings, {@code null} if null String was input
7585      * @since 2.4
7586      */
7587     public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
7588         return splitByWholeSeparatorWorker(str, separator, max, true);
7589     }
7590 
7591     /**
7592      * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
7593      *
7594      * @param str  the String to parse, may be {@code null}
7595      * @param separator  String containing the String to be used as a delimiter,
7596      *  {@code null} splits on whitespace
7597      * @param max  the maximum number of elements to include in the returned
7598      *  array. A zero or negative value implies no limit.
7599      * @param preserveAllTokens if {@code true}, adjacent separators are
7600      * treated as empty token separators; if {@code false}, adjacent
7601      * separators are treated as one separator.
7602      * @return an array of parsed Strings, {@code null} if null String input
7603      * @since 2.4
7604      */
7605     private static String[] splitByWholeSeparatorWorker(
7606             final String str, final String separator, final int max, final boolean preserveAllTokens) {
7607         if (str == null) {
7608             return null;
7609         }
7610 
7611         final int len = str.length();
7612 
7613         if (len == 0) {
7614             return ArrayUtils.EMPTY_STRING_ARRAY;
7615         }
7616 
7617         if (separator == null || EMPTY.equals(separator)) {
7618             // Split on whitespace.
7619             return splitWorker(str, null, max, preserveAllTokens);
7620         }
7621 
7622         final int separatorLength = separator.length();
7623 
7624         final ArrayList<String> substrings = new ArrayList<>();
7625         int numberOfSubstrings = 0;
7626         int beg = 0;
7627         int end = 0;
7628         while (end < len) {
7629             end = str.indexOf(separator, beg);
7630 
7631             if (end > -1) {
7632                 if (end > beg) {
7633                     numberOfSubstrings += 1;
7634 
7635                     if (numberOfSubstrings == max) {
7636                         end = len;
7637                         substrings.add(str.substring(beg));
7638                     } else {
7639                         // The following is OK, because String.substring( beg, end ) excludes
7640                         // the character at the position 'end'.
7641                         substrings.add(str.substring(beg, end));
7642 
7643                         // Set the starting point for the next search.
7644                         // The following is equivalent to beg = end + (separatorLength - 1) + 1,
7645                         // which is the right calculation:
7646                         beg = end + separatorLength;
7647                     }
7648                 } else {
7649                     // We found a consecutive occurrence of the separator, so skip it.
7650                     if (preserveAllTokens) {
7651                         numberOfSubstrings += 1;
7652                         if (numberOfSubstrings == max) {
7653                             end = len;
7654                             substrings.add(str.substring(beg));
7655                         } else {
7656                             substrings.add(EMPTY);
7657                         }
7658                     }
7659                     beg = end + separatorLength;
7660                 }
7661             } else {
7662                 // String.substring( beg ) goes from 'beg' to the end of the String.
7663                 substrings.add(str.substring(beg));
7664                 end = len;
7665             }
7666         }
7667 
7668         return substrings.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7669     }
7670 
7671     /**
7672      * Splits the provided text into an array, using whitespace as the
7673      * separator, preserving all tokens, including empty tokens created by
7674      * adjacent separators. This is an alternative to using StringTokenizer.
7675      * Whitespace is defined by {@link Character#isWhitespace(char)}.
7676      *
7677      * <p>The separator is not included in the returned String array.
7678      * Adjacent separators are treated as separators for empty tokens.
7679      * For more control over the split use the StrTokenizer class.</p>
7680      *
7681      * <p>A {@code null} input String returns {@code null}.</p>
7682      *
7683      * <pre>
7684      * StringUtils.splitPreserveAllTokens(null)       = null
7685      * StringUtils.splitPreserveAllTokens("")         = []
7686      * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
7687      * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
7688      * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
7689      * </pre>
7690      *
7691      * @param str  the String to parse, may be {@code null}
7692      * @return an array of parsed Strings, {@code null} if null String input
7693      * @since 2.1
7694      */
7695     public static String[] splitPreserveAllTokens(final String str) {
7696         return splitWorker(str, null, -1, true);
7697     }
7698 
7699     /**
7700      * Splits the provided text into an array, separator specified,
7701      * preserving all tokens, including empty tokens created by adjacent
7702      * separators. This is an alternative to using StringTokenizer.
7703      *
7704      * <p>The separator is not included in the returned String array.
7705      * Adjacent separators are treated as separators for empty tokens.
7706      * For more control over the split use the StrTokenizer class.</p>
7707      *
7708      * <p>A {@code null} input String returns {@code null}.</p>
7709      *
7710      * <pre>
7711      * StringUtils.splitPreserveAllTokens(null, *)         = null
7712      * StringUtils.splitPreserveAllTokens("", *)           = []
7713      * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
7714      * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
7715      * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
7716      * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
7717      * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
7718      * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
7719      * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
7720      * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
7721      * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
7722      * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
7723      * </pre>
7724      *
7725      * @param str  the String to parse, may be {@code null}
7726      * @param separatorChar  the character used as the delimiter,
7727      *  {@code null} splits on whitespace
7728      * @return an array of parsed Strings, {@code null} if null String input
7729      * @since 2.1
7730      */
7731     public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
7732         return splitWorker(str, separatorChar, true);
7733     }
7734 
7735     /**
7736      * Splits the provided text into an array, separators specified,
7737      * preserving all tokens, including empty tokens created by adjacent
7738      * separators. This is an alternative to using StringTokenizer.
7739      *
7740      * <p>The separator is not included in the returned String array.
7741      * Adjacent separators are treated as separators for empty tokens.
7742      * For more control over the split use the StrTokenizer class.</p>
7743      *
7744      * <p>A {@code null} input String returns {@code null}.
7745      * A {@code null} separatorChars splits on whitespace.</p>
7746      *
7747      * <pre>
7748      * StringUtils.splitPreserveAllTokens(null, *)           = null
7749      * StringUtils.splitPreserveAllTokens("", *)             = []
7750      * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
7751      * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
7752      * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
7753      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
7754      * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
7755      * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
7756      * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
7757      * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
7758      * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
7759      * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
7760      * </pre>
7761      *
7762      * @param str  the String to parse, may be {@code null}
7763      * @param separatorChars  the characters used as the delimiters,
7764      *  {@code null} splits on whitespace
7765      * @return an array of parsed Strings, {@code null} if null String input
7766      * @since 2.1
7767      */
7768     public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
7769         return splitWorker(str, separatorChars, -1, true);
7770     }
7771 
7772     /**
7773      * Splits the provided text into an array with a maximum length,
7774      * separators specified, preserving all tokens, including empty tokens
7775      * created by adjacent separators.
7776      *
7777      * <p>The separator is not included in the returned String array.
7778      * Adjacent separators are treated as separators for empty tokens.
7779      * Adjacent separators are treated as one separator.</p>
7780      *
7781      * <p>A {@code null} input String returns {@code null}.
7782      * A {@code null} separatorChars splits on whitespace.</p>
7783      *
7784      * <p>If more than {@code max} delimited substrings are found, the last
7785      * returned string includes all characters after the first {@code max - 1}
7786      * returned strings (including separator characters).</p>
7787      *
7788      * <pre>
7789      * StringUtils.splitPreserveAllTokens(null, *, *)            = null
7790      * StringUtils.splitPreserveAllTokens("", *, *)              = []
7791      * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "de", "fg"]
7792      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "", "", "de", "fg"]
7793      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
7794      * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
7795      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
7796      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
7797      * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
7798      * </pre>
7799      *
7800      * @param str  the String to parse, may be {@code null}
7801      * @param separatorChars  the characters used as the delimiters,
7802      *  {@code null} splits on whitespace
7803      * @param max  the maximum number of elements to include in the
7804      *  array. A zero or negative value implies no limit
7805      * @return an array of parsed Strings, {@code null} if null String input
7806      * @since 2.1
7807      */
7808     public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
7809         return splitWorker(str, separatorChars, max, true);
7810     }
7811 
7812     /**
7813      * Performs the logic for the {@code split} and
7814      * {@code splitPreserveAllTokens} methods that do not return a
7815      * maximum array length.
7816      *
7817      * @param str  the String to parse, may be {@code null}
7818      * @param separatorChar the separate character
7819      * @param preserveAllTokens if {@code true}, adjacent separators are
7820      * treated as empty token separators; if {@code false}, adjacent
7821      * separators are treated as one separator.
7822      * @return an array of parsed Strings, {@code null} if null String input
7823      */
7824     private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
7825         // Performance tuned for 2.0 (JDK1.4)
7826 
7827         if (str == null) {
7828             return null;
7829         }
7830         final int len = str.length();
7831         if (len == 0) {
7832             return ArrayUtils.EMPTY_STRING_ARRAY;
7833         }
7834         final List<String> list = new ArrayList<>();
7835         int i = 0;
7836         int start = 0;
7837         boolean match = false;
7838         boolean lastMatch = false;
7839         while (i < len) {
7840             if (str.charAt(i) == separatorChar) {
7841                 if (match || preserveAllTokens) {
7842                     list.add(str.substring(start, i));
7843                     match = false;
7844                     lastMatch = true;
7845                 }
7846                 start = ++i;
7847                 continue;
7848             }
7849             lastMatch = false;
7850             match = true;
7851             i++;
7852         }
7853         if (match || preserveAllTokens && lastMatch) {
7854             list.add(str.substring(start, i));
7855         }
7856         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7857     }
7858 
7859     /**
7860      * Performs the logic for the {@code split} and
7861      * {@code splitPreserveAllTokens} methods that return a maximum array
7862      * length.
7863      *
7864      * @param str  the String to parse, may be {@code null}
7865      * @param separatorChars the separate character
7866      * @param max  the maximum number of elements to include in the
7867      *  array. A zero or negative value implies no limit.
7868      * @param preserveAllTokens if {@code true}, adjacent separators are
7869      * treated as empty token separators; if {@code false}, adjacent
7870      * separators are treated as one separator.
7871      * @return an array of parsed Strings, {@code null} if null String input
7872      */
7873     private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
7874         // Performance tuned for 2.0 (JDK1.4)
7875         // Direct code is quicker than StringTokenizer.
7876         // Also, StringTokenizer uses isSpace() not isWhitespace()
7877 
7878         if (str == null) {
7879             return null;
7880         }
7881         final int len = str.length();
7882         if (len == 0) {
7883             return ArrayUtils.EMPTY_STRING_ARRAY;
7884         }
7885         final List<String> list = new ArrayList<>();
7886         int sizePlus1 = 1;
7887         int i = 0;
7888         int start = 0;
7889         boolean match = false;
7890         boolean lastMatch = false;
7891         if (separatorChars == null) {
7892             // Null separator means use whitespace
7893             while (i < len) {
7894                 if (Character.isWhitespace(str.charAt(i))) {
7895                     if (match || preserveAllTokens) {
7896                         lastMatch = true;
7897                         if (sizePlus1++ == max) {
7898                             i = len;
7899                             lastMatch = false;
7900                         }
7901                         list.add(str.substring(start, i));
7902                         match = false;
7903                     }
7904                     start = ++i;
7905                     continue;
7906                 }
7907                 lastMatch = false;
7908                 match = true;
7909                 i++;
7910             }
7911         } else if (separatorChars.length() == 1) {
7912             // Optimise 1 character case
7913             final char sep = separatorChars.charAt(0);
7914             while (i < len) {
7915                 if (str.charAt(i) == sep) {
7916                     if (match || preserveAllTokens) {
7917                         lastMatch = true;
7918                         if (sizePlus1++ == max) {
7919                             i = len;
7920                             lastMatch = false;
7921                         }
7922                         list.add(str.substring(start, i));
7923                         match = false;
7924                     }
7925                     start = ++i;
7926                     continue;
7927                 }
7928                 lastMatch = false;
7929                 match = true;
7930                 i++;
7931             }
7932         } else {
7933             // standard case
7934             while (i < len) {
7935                 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
7936                     if (match || preserveAllTokens) {
7937                         lastMatch = true;
7938                         if (sizePlus1++ == max) {
7939                             i = len;
7940                             lastMatch = false;
7941                         }
7942                         list.add(str.substring(start, i));
7943                         match = false;
7944                     }
7945                     start = ++i;
7946                     continue;
7947                 }
7948                 lastMatch = false;
7949                 match = true;
7950                 i++;
7951             }
7952         }
7953         if (match || preserveAllTokens && lastMatch) {
7954             list.add(str.substring(start, i));
7955         }
7956         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
7957     }
7958 
7959     /**
7960      * Check if a CharSequence starts with a specified prefix.
7961      *
7962      * <p>{@code null}s are handled without exceptions. Two {@code null}
7963      * references are considered to be equal. The comparison is case-sensitive.</p>
7964      *
7965      * <pre>
7966      * StringUtils.startsWith(null, null)      = true
7967      * StringUtils.startsWith(null, "abc")     = false
7968      * StringUtils.startsWith("abcdef", null)  = false
7969      * StringUtils.startsWith("abcdef", "abc") = true
7970      * StringUtils.startsWith("ABCDEF", "abc") = false
7971      * </pre>
7972      *
7973      * @see String#startsWith(String)
7974      * @param str  the CharSequence to check, may be null
7975      * @param prefix the prefix to find, may be null
7976      * @return {@code true} if the CharSequence starts with the prefix, case-sensitive, or
7977      *  both {@code null}
7978      * @since 2.4
7979      * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
7980      */
7981     public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
7982         return startsWith(str, prefix, false);
7983     }
7984 
7985     /**
7986      * Check if a CharSequence starts with a specified prefix (optionally case insensitive).
7987      *
7988      * @see String#startsWith(String)
7989      * @param str  the CharSequence to check, may be null
7990      * @param prefix the prefix to find, may be null
7991      * @param ignoreCase indicates whether the compare should ignore case
7992      *  (case-insensitive) or not.
7993      * @return {@code true} if the CharSequence starts with the prefix or
7994      *  both {@code null}
7995      */
7996     private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
7997         if (str == null || prefix == null) {
7998             return str == prefix;
7999         }
8000         // Get length once instead of twice in the unlikely case that it changes.
8001         final int preLen = prefix.length();
8002         if (preLen > str.length()) {
8003             return false;
8004         }
8005         return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, preLen);
8006     }
8007 
8008     /**
8009      * Check if a CharSequence starts with any of the provided case-sensitive prefixes.
8010      *
8011      * <pre>
8012      * StringUtils.startsWithAny(null, null)      = false
8013      * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
8014      * StringUtils.startsWithAny("abcxyz", null)     = false
8015      * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8016      * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8017      * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8018      * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8019      * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8020      * </pre>
8021      *
8022      * @param sequence the CharSequence to check, may be null
8023      * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8024      * @see StringUtils#startsWith(CharSequence, CharSequence)
8025      * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8026      *   the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8027      * @since 2.5
8028      * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8029      */
8030     public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8031         if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8032             return false;
8033         }
8034         for (final CharSequence searchString : searchStrings) {
8035             if (startsWith(sequence, searchString)) {
8036                 return true;
8037             }
8038         }
8039         return false;
8040     }
8041 
8042     /**
8043      * Case insensitive check if a CharSequence starts with a specified prefix.
8044      *
8045      * <p>{@code null}s are handled without exceptions. Two {@code null}
8046      * references are considered to be equal. The comparison is case insensitive.</p>
8047      *
8048      * <pre>
8049      * StringUtils.startsWithIgnoreCase(null, null)      = true
8050      * StringUtils.startsWithIgnoreCase(null, "abc")     = false
8051      * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
8052      * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8053      * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8054      * </pre>
8055      *
8056      * @see String#startsWith(String)
8057      * @param str  the CharSequence to check, may be null
8058      * @param prefix the prefix to find, may be null
8059      * @return {@code true} if the CharSequence starts with the prefix, case-insensitive, or
8060      *  both {@code null}
8061      * @since 2.4
8062      * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8063      */
8064     public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8065         return startsWith(str, prefix, true);
8066     }
8067 
8068     /**
8069      * Strips whitespace from the start and end of a String.
8070      *
8071      * <p>This is similar to {@link #trim(String)} but removes whitespace.
8072      * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8073      *
8074      * <p>A {@code null} input String returns {@code null}.</p>
8075      *
8076      * <pre>
8077      * StringUtils.strip(null)     = null
8078      * StringUtils.strip("")       = ""
8079      * StringUtils.strip("   ")    = ""
8080      * StringUtils.strip("abc")    = "abc"
8081      * StringUtils.strip("  abc")  = "abc"
8082      * StringUtils.strip("abc  ")  = "abc"
8083      * StringUtils.strip(" abc ")  = "abc"
8084      * StringUtils.strip(" ab c ") = "ab c"
8085      * </pre>
8086      *
8087      * @param str  the String to remove whitespace from, may be null
8088      * @return the stripped String, {@code null} if null String input
8089      */
8090     public static String strip(final String str) {
8091         return strip(str, null);
8092     }
8093 
8094     /**
8095      * Strips any of a set of characters from the start and end of a String.
8096      * This is similar to {@link String#trim()} but allows the characters
8097      * to be stripped to be controlled.
8098      *
8099      * <p>A {@code null} input String returns {@code null}.
8100      * An empty string ("") input returns the empty string.</p>
8101      *
8102      * <p>If the stripChars String is {@code null}, whitespace is
8103      * stripped as defined by {@link Character#isWhitespace(char)}.
8104      * Alternatively use {@link #strip(String)}.</p>
8105      *
8106      * <pre>
8107      * StringUtils.strip(null, *)          = null
8108      * StringUtils.strip("", *)            = ""
8109      * StringUtils.strip("abc", null)      = "abc"
8110      * StringUtils.strip("  abc", null)    = "abc"
8111      * StringUtils.strip("abc  ", null)    = "abc"
8112      * StringUtils.strip(" abc ", null)    = "abc"
8113      * StringUtils.strip("  abcyx", "xyz") = "  abc"
8114      * </pre>
8115      *
8116      * @param str  the String to remove characters from, may be null
8117      * @param stripChars  the characters to remove, null treated as whitespace
8118      * @return the stripped String, {@code null} if null String input
8119      */
8120     public static String strip(String str, final String stripChars) {
8121         str = stripStart(str, stripChars);
8122         return stripEnd(str, stripChars);
8123     }
8124 
8125     /**
8126      * Removes diacritics (~= accents) from a string. The case will not be altered.
8127      * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
8128      * <p>Note that ligatures will be left as is.</p>
8129      *
8130      * <pre>
8131      * StringUtils.stripAccents(null)                = null
8132      * StringUtils.stripAccents("")                  = ""
8133      * StringUtils.stripAccents("control")           = "control"
8134      * StringUtils.stripAccents("&eacute;clair")     = "eclair"
8135      * </pre>
8136      *
8137      * @param input String to be stripped
8138      * @return input text with diacritics removed
8139      *
8140      * @since 3.0
8141      */
8142     // 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).
8143     public static String stripAccents(final String input) {
8144         if (input == null) {
8145             return null;
8146         }
8147         final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
8148         convertRemainingAccentCharacters(decomposed);
8149         // Note that this doesn't correctly remove ligatures...
8150         return STRIP_ACCENTS_PATTERN.matcher(decomposed).replaceAll(EMPTY);
8151     }
8152 
8153     /**
8154      * Strips whitespace from the start and end of every String in an array.
8155      * Whitespace is defined by {@link Character#isWhitespace(char)}.
8156      *
8157      * <p>A new array is returned each time, except for length zero.
8158      * A {@code null} array will return {@code null}.
8159      * An empty array will return itself.
8160      * A {@code null} array entry will be ignored.</p>
8161      *
8162      * <pre>
8163      * StringUtils.stripAll(null)             = null
8164      * StringUtils.stripAll([])               = []
8165      * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
8166      * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
8167      * </pre>
8168      *
8169      * @param strs  the array to remove whitespace from, may be null
8170      * @return the stripped Strings, {@code null} if null array input
8171      */
8172     public static String[] stripAll(final String... strs) {
8173         return stripAll(strs, null);
8174     }
8175 
8176     /**
8177      * Strips any of a set of characters from the start and end of every
8178      * String in an array.
8179      * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8180      *
8181      * <p>A new array is returned each time, except for length zero.
8182      * A {@code null} array will return {@code null}.
8183      * An empty array will return itself.
8184      * A {@code null} array entry will be ignored.
8185      * A {@code null} stripChars will strip whitespace as defined by
8186      * {@link Character#isWhitespace(char)}.</p>
8187      *
8188      * <pre>
8189      * StringUtils.stripAll(null, *)                = null
8190      * StringUtils.stripAll([], *)                  = []
8191      * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
8192      * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
8193      * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
8194      * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
8195      * </pre>
8196      *
8197      * @param strs  the array to remove characters from, may be null
8198      * @param stripChars  the characters to remove, null treated as whitespace
8199      * @return the stripped Strings, {@code null} if null array input
8200      */
8201     public static String[] stripAll(final String[] strs, final String stripChars) {
8202         final int strsLen = ArrayUtils.getLength(strs);
8203         if (strsLen == 0) {
8204             return strs;
8205         }
8206         final String[] newArr = new String[strsLen];
8207         Arrays.setAll(newArr, i -> strip(strs[i], stripChars));
8208         return newArr;
8209     }
8210 
8211     /**
8212      * Strips any of a set of characters from the end of a String.
8213      *
8214      * <p>A {@code null} input String returns {@code null}.
8215      * An empty string ("") input returns the empty string.</p>
8216      *
8217      * <p>If the stripChars String is {@code null}, whitespace is
8218      * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8219      *
8220      * <pre>
8221      * StringUtils.stripEnd(null, *)          = null
8222      * StringUtils.stripEnd("", *)            = ""
8223      * StringUtils.stripEnd("abc", "")        = "abc"
8224      * StringUtils.stripEnd("abc", null)      = "abc"
8225      * StringUtils.stripEnd("  abc", null)    = "  abc"
8226      * StringUtils.stripEnd("abc  ", null)    = "abc"
8227      * StringUtils.stripEnd(" abc ", null)    = " abc"
8228      * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
8229      * StringUtils.stripEnd("120.00", ".0")   = "12"
8230      * </pre>
8231      *
8232      * @param str  the String to remove characters from, may be null
8233      * @param stripChars  the set of characters to remove, null treated as whitespace
8234      * @return the stripped String, {@code null} if null String input
8235      */
8236     public static String stripEnd(final String str, final String stripChars) {
8237         int end = length(str);
8238         if (end == 0) {
8239             return str;
8240         }
8241 
8242         if (stripChars == null) {
8243             while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
8244                 end--;
8245             }
8246         } else if (stripChars.isEmpty()) {
8247             return str;
8248         } else {
8249             while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
8250                 end--;
8251             }
8252         }
8253         return str.substring(0, end);
8254     }
8255 
8256     /**
8257      * Strips any of a set of characters from the start of a String.
8258      *
8259      * <p>A {@code null} input String returns {@code null}.
8260      * An empty string ("") input returns the empty string.</p>
8261      *
8262      * <p>If the stripChars String is {@code null}, whitespace is
8263      * stripped as defined by {@link Character#isWhitespace(char)}.</p>
8264      *
8265      * <pre>
8266      * StringUtils.stripStart(null, *)          = null
8267      * StringUtils.stripStart("", *)            = ""
8268      * StringUtils.stripStart("abc", "")        = "abc"
8269      * StringUtils.stripStart("abc", null)      = "abc"
8270      * StringUtils.stripStart("  abc", null)    = "abc"
8271      * StringUtils.stripStart("abc  ", null)    = "abc  "
8272      * StringUtils.stripStart(" abc ", null)    = "abc "
8273      * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
8274      * </pre>
8275      *
8276      * @param str  the String to remove characters from, may be null
8277      * @param stripChars  the characters to remove, null treated as whitespace
8278      * @return the stripped String, {@code null} if null String input
8279      */
8280     public static String stripStart(final String str, final String stripChars) {
8281         final int strLen = length(str);
8282         if (strLen == 0) {
8283             return str;
8284         }
8285         int start = 0;
8286         if (stripChars == null) {
8287             while (start != strLen && Character.isWhitespace(str.charAt(start))) {
8288                 start++;
8289             }
8290         } else if (stripChars.isEmpty()) {
8291             return str;
8292         } else {
8293             while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
8294                 start++;
8295             }
8296         }
8297         return str.substring(start);
8298     }
8299 
8300     /**
8301      * Strips whitespace from the start and end of a String  returning
8302      * an empty String if {@code null} input.
8303      *
8304      * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
8305      * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8306      *
8307      * <pre>
8308      * StringUtils.stripToEmpty(null)     = ""
8309      * StringUtils.stripToEmpty("")       = ""
8310      * StringUtils.stripToEmpty("   ")    = ""
8311      * StringUtils.stripToEmpty("abc")    = "abc"
8312      * StringUtils.stripToEmpty("  abc")  = "abc"
8313      * StringUtils.stripToEmpty("abc  ")  = "abc"
8314      * StringUtils.stripToEmpty(" abc ")  = "abc"
8315      * StringUtils.stripToEmpty(" ab c ") = "ab c"
8316      * </pre>
8317      *
8318      * @param str  the String to be stripped, may be null
8319      * @return the trimmed String, or an empty String if {@code null} input
8320      * @since 2.0
8321      */
8322     public static String stripToEmpty(final String str) {
8323         return str == null ? EMPTY : strip(str, null);
8324     }
8325 
8326     /**
8327      * Strips whitespace from the start and end of a String  returning
8328      * {@code null} if the String is empty ("") after the strip.
8329      *
8330      * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
8331      * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
8332      *
8333      * <pre>
8334      * StringUtils.stripToNull(null)     = null
8335      * StringUtils.stripToNull("")       = null
8336      * StringUtils.stripToNull("   ")    = null
8337      * StringUtils.stripToNull("abc")    = "abc"
8338      * StringUtils.stripToNull("  abc")  = "abc"
8339      * StringUtils.stripToNull("abc  ")  = "abc"
8340      * StringUtils.stripToNull(" abc ")  = "abc"
8341      * StringUtils.stripToNull(" ab c ") = "ab c"
8342      * </pre>
8343      *
8344      * @param str  the String to be stripped, may be null
8345      * @return the stripped String,
8346      *  {@code null} if whitespace, empty or null String input
8347      * @since 2.0
8348      */
8349     public static String stripToNull(String str) {
8350         if (str == null) {
8351             return null;
8352         }
8353         str = strip(str, null);
8354         return str.isEmpty() ? null : str; // NOSONARLINT str cannot be null here
8355     }
8356 
8357     /**
8358      * Gets a substring from the specified String avoiding exceptions.
8359      *
8360      * <p>A negative start position can be used to start {@code n}
8361      * characters from the end of the String.</p>
8362      *
8363      * <p>A {@code null} String will return {@code null}.
8364      * An empty ("") String will return "".</p>
8365      *
8366      * <pre>
8367      * StringUtils.substring(null, *)   = null
8368      * StringUtils.substring("", *)     = ""
8369      * StringUtils.substring("abc", 0)  = "abc"
8370      * StringUtils.substring("abc", 2)  = "c"
8371      * StringUtils.substring("abc", 4)  = ""
8372      * StringUtils.substring("abc", -2) = "bc"
8373      * StringUtils.substring("abc", -4) = "abc"
8374      * </pre>
8375      *
8376      * @param str  the String to get the substring from, may be null
8377      * @param start  the position to start from, negative means
8378      *  count back from the end of the String by this many characters
8379      * @return substring from start position, {@code null} if null String input
8380      */
8381     public static String substring(final String str, int start) {
8382         if (str == null) {
8383             return null;
8384         }
8385 
8386         // handle negatives, which means last n characters
8387         if (start < 0) {
8388             start = str.length() + start; // remember start is negative
8389         }
8390 
8391         if (start < 0) {
8392             start = 0;
8393         }
8394         if (start > str.length()) {
8395             return EMPTY;
8396         }
8397 
8398         return str.substring(start);
8399     }
8400 
8401     /**
8402      * Gets a substring from the specified String avoiding exceptions.
8403      *
8404      * <p>A negative start position can be used to start/end {@code n}
8405      * characters from the end of the String.</p>
8406      *
8407      * <p>The returned substring starts with the character in the {@code start}
8408      * position and ends before the {@code end} position. All position counting is
8409      * zero-based -- i.e., to start at the beginning of the string use
8410      * {@code start = 0}. Negative start and end positions can be used to
8411      * specify offsets relative to the end of the String.</p>
8412      *
8413      * <p>If {@code start} is not strictly to the left of {@code end}, ""
8414      * is returned.</p>
8415      *
8416      * <pre>
8417      * StringUtils.substring(null, *, *)    = null
8418      * StringUtils.substring("", * ,  *)    = "";
8419      * StringUtils.substring("abc", 0, 2)   = "ab"
8420      * StringUtils.substring("abc", 2, 0)   = ""
8421      * StringUtils.substring("abc", 2, 4)   = "c"
8422      * StringUtils.substring("abc", 4, 6)   = ""
8423      * StringUtils.substring("abc", 2, 2)   = ""
8424      * StringUtils.substring("abc", -2, -1) = "b"
8425      * StringUtils.substring("abc", -4, 2)  = "ab"
8426      * </pre>
8427      *
8428      * @param str  the String to get the substring from, may be null
8429      * @param start  the position to start from, negative means
8430      *  count back from the end of the String by this many characters
8431      * @param end  the position to end at (exclusive), negative means
8432      *  count back from the end of the String by this many characters
8433      * @return substring from start position to end position,
8434      *  {@code null} if null String input
8435      */
8436     public static String substring(final String str, int start, int end) {
8437         if (str == null) {
8438             return null;
8439         }
8440 
8441         // handle negatives
8442         if (end < 0) {
8443             end = str.length() + end; // remember end is negative
8444         }
8445         if (start < 0) {
8446             start = str.length() + start; // remember start is negative
8447         }
8448 
8449         // check length next
8450         if (end > str.length()) {
8451             end = str.length();
8452         }
8453 
8454         // if start is greater than end, return ""
8455         if (start > end) {
8456             return EMPTY;
8457         }
8458 
8459         if (start < 0) {
8460             start = 0;
8461         }
8462         if (end < 0) {
8463             end = 0;
8464         }
8465 
8466         return str.substring(start, end);
8467     }
8468 
8469     /**
8470      * Gets the substring after the first occurrence of a separator.
8471      * The separator is not returned.
8472      *
8473      * <p>A {@code null} string input will return {@code null}.
8474      * An empty ("") string input will return the empty string.
8475      *
8476      * <p>If nothing is found, the empty string is returned.</p>
8477      *
8478      * <pre>
8479      * StringUtils.substringAfter(null, *)      = null
8480      * StringUtils.substringAfter("", *)        = ""
8481      * StringUtils.substringAfter("abc", 'a')   = "bc"
8482      * StringUtils.substringAfter("abcba", 'b') = "cba"
8483      * StringUtils.substringAfter("abc", 'c')   = ""
8484      * StringUtils.substringAfter("abc", 'd')   = ""
8485      * StringUtils.substringAfter(" abc", 32)   = "abc"
8486      * </pre>
8487      *
8488      * @param str  the String to get a substring from, may be null
8489      * @param separator  the character (Unicode code point) to search.
8490      * @return the substring after the first occurrence of the separator,
8491      *  {@code null} if null String input
8492      * @since 3.11
8493      */
8494     public static String substringAfter(final String str, final int separator) {
8495         if (isEmpty(str)) {
8496             return str;
8497         }
8498         final int pos = str.indexOf(separator);
8499         if (pos == INDEX_NOT_FOUND) {
8500             return EMPTY;
8501         }
8502         return str.substring(pos + 1);
8503     }
8504 
8505     /**
8506      * Gets the substring after the first occurrence of a separator.
8507      * The separator is not returned.
8508      *
8509      * <p>A {@code null} string input will return {@code null}.
8510      * An empty ("") string input will return the empty string.
8511      * A {@code null} separator will return the empty string if the
8512      * input string is not {@code null}.</p>
8513      *
8514      * <p>If nothing is found, the empty string is returned.</p>
8515      *
8516      * <pre>
8517      * StringUtils.substringAfter(null, *)      = null
8518      * StringUtils.substringAfter("", *)        = ""
8519      * StringUtils.substringAfter(*, null)      = ""
8520      * StringUtils.substringAfter("abc", "a")   = "bc"
8521      * StringUtils.substringAfter("abcba", "b") = "cba"
8522      * StringUtils.substringAfter("abc", "c")   = ""
8523      * StringUtils.substringAfter("abc", "d")   = ""
8524      * StringUtils.substringAfter("abc", "")    = "abc"
8525      * </pre>
8526      *
8527      * @param str  the String to get a substring from, may be null
8528      * @param separator  the String to search for, may be null
8529      * @return the substring after the first occurrence of the separator,
8530      *  {@code null} if null String input
8531      * @since 2.0
8532      */
8533     public static String substringAfter(final String str, final String separator) {
8534         if (isEmpty(str)) {
8535             return str;
8536         }
8537         if (separator == null) {
8538             return EMPTY;
8539         }
8540         final int pos = str.indexOf(separator);
8541         if (pos == INDEX_NOT_FOUND) {
8542             return EMPTY;
8543         }
8544         return str.substring(pos + separator.length());
8545     }
8546 
8547     /**
8548      * Gets the substring after the last occurrence of a separator.
8549      * The separator is not returned.
8550      *
8551      * <p>A {@code null} string input will return {@code null}.
8552      * An empty ("") string input will return the empty string.
8553      *
8554      * <p>If nothing is found, the empty string is returned.</p>
8555      *
8556      * <pre>
8557      * StringUtils.substringAfterLast(null, *)      = null
8558      * StringUtils.substringAfterLast("", *)        = ""
8559      * StringUtils.substringAfterLast("abc", 'a')   = "bc"
8560      * StringUtils.substringAfterLast(" bc", 32)    = "bc"
8561      * StringUtils.substringAfterLast("abcba", 'b') = "a"
8562      * StringUtils.substringAfterLast("abc", 'c')   = ""
8563      * StringUtils.substringAfterLast("a", 'a')     = ""
8564      * StringUtils.substringAfterLast("a", 'z')     = ""
8565      * </pre>
8566      *
8567      * @param str  the String to get a substring from, may be null
8568      * @param separator  the character (Unicode code point) to search.
8569      * @return the substring after the last occurrence of the separator,
8570      *  {@code null} if null String input
8571      * @since 3.11
8572      */
8573     public static String substringAfterLast(final String str, final int separator) {
8574         if (isEmpty(str)) {
8575             return str;
8576         }
8577         final int pos = str.lastIndexOf(separator);
8578         if (pos == INDEX_NOT_FOUND || pos == str.length() - 1) {
8579             return EMPTY;
8580         }
8581         return str.substring(pos + 1);
8582     }
8583 
8584     /**
8585      * Gets the substring after the last occurrence of a separator.
8586      * The separator is not returned.
8587      *
8588      * <p>A {@code null} string input will return {@code null}.
8589      * An empty ("") string input will return the empty string.
8590      * An empty or {@code null} separator will return the empty string if
8591      * the input string is not {@code null}.</p>
8592      *
8593      * <p>If nothing is found, the empty string is returned.</p>
8594      *
8595      * <pre>
8596      * StringUtils.substringAfterLast(null, *)      = null
8597      * StringUtils.substringAfterLast("", *)        = ""
8598      * StringUtils.substringAfterLast(*, "")        = ""
8599      * StringUtils.substringAfterLast(*, null)      = ""
8600      * StringUtils.substringAfterLast("abc", "a")   = "bc"
8601      * StringUtils.substringAfterLast("abcba", "b") = "a"
8602      * StringUtils.substringAfterLast("abc", "c")   = ""
8603      * StringUtils.substringAfterLast("a", "a")     = ""
8604      * StringUtils.substringAfterLast("a", "z")     = ""
8605      * </pre>
8606      *
8607      * @param str  the String to get a substring from, may be null
8608      * @param separator  the String to search for, may be null
8609      * @return the substring after the last occurrence of the separator,
8610      *  {@code null} if null String input
8611      * @since 2.0
8612      */
8613     public static String substringAfterLast(final String str, final String separator) {
8614         if (isEmpty(str)) {
8615             return str;
8616         }
8617         if (isEmpty(separator)) {
8618             return EMPTY;
8619         }
8620         final int pos = str.lastIndexOf(separator);
8621         if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
8622             return EMPTY;
8623         }
8624         return str.substring(pos + separator.length());
8625     }
8626 
8627     /**
8628      * Gets the substring before the first occurrence of a separator. The separator is not returned.
8629      *
8630      * <p>
8631      * A {@code null} string input will return {@code null}. An empty ("") string input will return the empty string.
8632      * </p>
8633      *
8634      * <p>
8635      * If nothing is found, the string input is returned.
8636      * </p>
8637      *
8638      * <pre>
8639      * StringUtils.substringBefore(null, *)      = null
8640      * StringUtils.substringBefore("", *)        = ""
8641      * StringUtils.substringBefore("abc", 'a')   = ""
8642      * StringUtils.substringBefore("abcba", 'b') = "a"
8643      * StringUtils.substringBefore("abc", 'c')   = "ab"
8644      * StringUtils.substringBefore("abc", 'd')   = "abc"
8645      * </pre>
8646      *
8647      * @param str the String to get a substring from, may be null
8648      * @param separator the character (Unicode code point) to search.
8649      * @return the substring before the first occurrence of the separator, {@code null} if null String input
8650      * @since 3.12.0
8651      */
8652     public static String substringBefore(final String str, final int separator) {
8653         if (isEmpty(str)) {
8654             return str;
8655         }
8656         final int pos = str.indexOf(separator);
8657         if (pos == INDEX_NOT_FOUND) {
8658             return str;
8659         }
8660         return str.substring(0, pos);
8661     }
8662 
8663     /**
8664      * Gets the substring before the first occurrence of a separator.
8665      * The separator is not returned.
8666      *
8667      * <p>A {@code null} string input will return {@code null}.
8668      * An empty ("") string input will return the empty string.
8669      * A {@code null} separator will return the input string.</p>
8670      *
8671      * <p>If nothing is found, the string input is returned.</p>
8672      *
8673      * <pre>
8674      * StringUtils.substringBefore(null, *)      = null
8675      * StringUtils.substringBefore("", *)        = ""
8676      * StringUtils.substringBefore("abc", "a")   = ""
8677      * StringUtils.substringBefore("abcba", "b") = "a"
8678      * StringUtils.substringBefore("abc", "c")   = "ab"
8679      * StringUtils.substringBefore("abc", "d")   = "abc"
8680      * StringUtils.substringBefore("abc", "")    = ""
8681      * StringUtils.substringBefore("abc", null)  = "abc"
8682      * </pre>
8683      *
8684      * @param str  the String to get a substring from, may be null
8685      * @param separator  the String to search for, may be null
8686      * @return the substring before the first occurrence of the separator,
8687      *  {@code null} if null String input
8688      * @since 2.0
8689      */
8690     public static String substringBefore(final String str, final String separator) {
8691         if (isEmpty(str) || separator == null) {
8692             return str;
8693         }
8694         if (separator.isEmpty()) {
8695             return EMPTY;
8696         }
8697         final int pos = str.indexOf(separator);
8698         if (pos == INDEX_NOT_FOUND) {
8699             return str;
8700         }
8701         return str.substring(0, pos);
8702     }
8703 
8704     /**
8705      * Gets the substring before the last occurrence of a separator.
8706      * The separator is not returned.
8707      *
8708      * <p>A {@code null} string input will return {@code null}.
8709      * An empty ("") string input will return the empty string.
8710      * An empty or {@code null} separator will return the input string.</p>
8711      *
8712      * <p>If nothing is found, the string input is returned.</p>
8713      *
8714      * <pre>
8715      * StringUtils.substringBeforeLast(null, *)      = null
8716      * StringUtils.substringBeforeLast("", *)        = ""
8717      * StringUtils.substringBeforeLast("abcba", "b") = "abc"
8718      * StringUtils.substringBeforeLast("abc", "c")   = "ab"
8719      * StringUtils.substringBeforeLast("a", "a")     = ""
8720      * StringUtils.substringBeforeLast("a", "z")     = "a"
8721      * StringUtils.substringBeforeLast("a", null)    = "a"
8722      * StringUtils.substringBeforeLast("a", "")      = "a"
8723      * </pre>
8724      *
8725      * @param str  the String to get a substring from, may be null
8726      * @param separator  the String to search for, may be null
8727      * @return the substring before the last occurrence of the separator,
8728      *  {@code null} if null String input
8729      * @since 2.0
8730      */
8731     public static String substringBeforeLast(final String str, final String separator) {
8732         if (isEmpty(str) || isEmpty(separator)) {
8733             return str;
8734         }
8735         final int pos = str.lastIndexOf(separator);
8736         if (pos == INDEX_NOT_FOUND) {
8737             return str;
8738         }
8739         return str.substring(0, pos);
8740     }
8741 
8742     /**
8743      * Gets the String that is nested in between two instances of the
8744      * same String.
8745      *
8746      * <p>A {@code null} input String returns {@code null}.
8747      * A {@code null} tag returns {@code null}.</p>
8748      *
8749      * <pre>
8750      * StringUtils.substringBetween(null, *)            = null
8751      * StringUtils.substringBetween("", "")             = ""
8752      * StringUtils.substringBetween("", "tag")          = null
8753      * StringUtils.substringBetween("tagabctag", null)  = null
8754      * StringUtils.substringBetween("tagabctag", "")    = ""
8755      * StringUtils.substringBetween("tagabctag", "tag") = "abc"
8756      * </pre>
8757      *
8758      * @param str  the String containing the substring, may be null
8759      * @param tag  the String before and after the substring, may be null
8760      * @return the substring, {@code null} if no match
8761      * @since 2.0
8762      */
8763     public static String substringBetween(final String str, final String tag) {
8764         return substringBetween(str, tag, tag);
8765     }
8766 
8767     /**
8768      * Gets the String that is nested in between two Strings.
8769      * Only the first match is returned.
8770      *
8771      * <p>A {@code null} input String returns {@code null}.
8772      * A {@code null} open/close returns {@code null} (no match).
8773      * An empty ("") open and close returns an empty string.</p>
8774      *
8775      * <pre>
8776      * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
8777      * StringUtils.substringBetween(null, *, *)          = null
8778      * StringUtils.substringBetween(*, null, *)          = null
8779      * StringUtils.substringBetween(*, *, null)          = null
8780      * StringUtils.substringBetween("", "", "")          = ""
8781      * StringUtils.substringBetween("", "", "]")         = null
8782      * StringUtils.substringBetween("", "[", "]")        = null
8783      * StringUtils.substringBetween("yabcz", "", "")     = ""
8784      * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
8785      * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
8786      * </pre>
8787      *
8788      * @param str  the String containing the substring, may be null
8789      * @param open  the String before the substring, may be null
8790      * @param close  the String after the substring, may be null
8791      * @return the substring, {@code null} if no match
8792      * @since 2.0
8793      */
8794     public static String substringBetween(final String str, final String open, final String close) {
8795         if (!ObjectUtils.allNotNull(str, open, close)) {
8796             return null;
8797         }
8798         final int start = str.indexOf(open);
8799         if (start != INDEX_NOT_FOUND) {
8800             final int end = str.indexOf(close, start + open.length());
8801             if (end != INDEX_NOT_FOUND) {
8802                 return str.substring(start + open.length(), end);
8803             }
8804         }
8805         return null;
8806     }
8807 
8808     /**
8809      * Searches a String for substrings delimited by a start and end tag,
8810      * returning all matching substrings in an array.
8811      *
8812      * <p>A {@code null} input String returns {@code null}.
8813      * A {@code null} open/close returns {@code null} (no match).
8814      * An empty ("") open/close returns {@code null} (no match).</p>
8815      *
8816      * <pre>
8817      * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
8818      * StringUtils.substringsBetween(null, *, *)            = null
8819      * StringUtils.substringsBetween(*, null, *)            = null
8820      * StringUtils.substringsBetween(*, *, null)            = null
8821      * StringUtils.substringsBetween("", "[", "]")          = []
8822      * </pre>
8823      *
8824      * @param str  the String containing the substrings, null returns null, empty returns empty
8825      * @param open  the String identifying the start of the substring, empty returns null
8826      * @param close  the String identifying the end of the substring, empty returns null
8827      * @return a String Array of substrings, or {@code null} if no match
8828      * @since 2.3
8829      */
8830     public static String[] substringsBetween(final String str, final String open, final String close) {
8831         if (str == null || isEmpty(open) || isEmpty(close)) {
8832             return null;
8833         }
8834         final int strLen = str.length();
8835         if (strLen == 0) {
8836             return ArrayUtils.EMPTY_STRING_ARRAY;
8837         }
8838         final int closeLen = close.length();
8839         final int openLen = open.length();
8840         final List<String> list = new ArrayList<>();
8841         int pos = 0;
8842         while (pos < strLen - closeLen) {
8843             int start = str.indexOf(open, pos);
8844             if (start < 0) {
8845                 break;
8846             }
8847             start += openLen;
8848             final int end = str.indexOf(close, start);
8849             if (end < 0) {
8850                 break;
8851             }
8852             list.add(str.substring(start, end));
8853             pos = end + closeLen;
8854         }
8855         if (list.isEmpty()) {
8856             return null;
8857         }
8858         return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
8859     }
8860 
8861     /**
8862      * Swaps the case of a String changing upper and title case to
8863      * lower case, and lower case to upper case.
8864      *
8865      * <ul>
8866      *  <li>Upper case character converts to Lower case</li>
8867      *  <li>Title case character converts to Lower case</li>
8868      *  <li>Lower case character converts to Upper case</li>
8869      * </ul>
8870      *
8871      * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#swapCase(String)}.
8872      * A {@code null} input String returns {@code null}.</p>
8873      *
8874      * <pre>
8875      * StringUtils.swapCase(null)                 = null
8876      * StringUtils.swapCase("")                   = ""
8877      * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
8878      * </pre>
8879      *
8880      * <p>NOTE: This method changed in Lang version 2.0.
8881      * It no longer performs a word based algorithm.
8882      * If you only use ASCII, you will notice no change.
8883      * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
8884      *
8885      * @param str  the String to swap case, may be null
8886      * @return the changed String, {@code null} if null String input
8887      */
8888     public static String swapCase(final String str) {
8889         if (isEmpty(str)) {
8890             return str;
8891         }
8892 
8893         final int strLen = str.length();
8894         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
8895         int outOffset = 0;
8896         for (int i = 0; i < strLen; ) {
8897             final int oldCodepoint = str.codePointAt(i);
8898             final int newCodePoint;
8899             if (Character.isUpperCase(oldCodepoint) || Character.isTitleCase(oldCodepoint)) {
8900                 newCodePoint = Character.toLowerCase(oldCodepoint);
8901             } else if (Character.isLowerCase(oldCodepoint)) {
8902                 newCodePoint = Character.toUpperCase(oldCodepoint);
8903             } else {
8904                 newCodePoint = oldCodepoint;
8905             }
8906             newCodePoints[outOffset++] = newCodePoint;
8907             i += Character.charCount(newCodePoint);
8908          }
8909         return new String(newCodePoints, 0, outOffset);
8910     }
8911 
8912     /**
8913      * Converts a {@link CharSequence} into an array of code points.
8914      *
8915      * <p>Valid pairs of surrogate code units will be converted into a single supplementary
8916      * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
8917      * a low surrogate not preceded by a high surrogate) will be returned as-is.</p>
8918      *
8919      * <pre>
8920      * StringUtils.toCodePoints(null)   =  null
8921      * StringUtils.toCodePoints("")     =  []  // empty array
8922      * </pre>
8923      *
8924      * @param cs the character sequence to convert
8925      * @return an array of code points
8926      * @since 3.6
8927      */
8928     public static int[] toCodePoints(final CharSequence cs) {
8929         if (cs == null) {
8930             return null;
8931         }
8932         if (cs.length() == 0) {
8933             return ArrayUtils.EMPTY_INT_ARRAY;
8934         }
8935 
8936         final String s = cs.toString();
8937         final int[] result = new int[s.codePointCount(0, s.length())];
8938         int index = 0;
8939         for (int i = 0; i < result.length; i++) {
8940             result[i] = s.codePointAt(index);
8941             index += Character.charCount(result[i]);
8942         }
8943         return result;
8944     }
8945 
8946     /**
8947      * Converts a {@code byte[]} to a String using the specified character encoding.
8948      *
8949      * @param bytes
8950      *            the byte array to read from
8951      * @param charset
8952      *            the encoding to use, if null then use the platform default
8953      * @return a new String
8954      * @throws NullPointerException
8955      *             if {@code bytes} is null
8956      * @since 3.2
8957      * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8958      */
8959     public static String toEncodedString(final byte[] bytes, final Charset charset) {
8960         return new String(bytes, Charsets.toCharset(charset));
8961     }
8962 
8963     /**
8964      * Converts the given source String as a lower-case using the {@link Locale#ROOT} locale in a null-safe manner.
8965      *
8966      * @param source A source String or null.
8967      * @return the given source String as a lower-case using the {@link Locale#ROOT} locale or null.
8968      * @since 3.10
8969      */
8970     public static String toRootLowerCase(final String source) {
8971         return source == null ? null : source.toLowerCase(Locale.ROOT);
8972     }
8973 
8974     /**
8975      * Converts the given source String as a upper-case using the {@link Locale#ROOT} locale in a null-safe manner.
8976      *
8977      * @param source A source String or null.
8978      * @return the given source String as a upper-case using the {@link Locale#ROOT} locale or null.
8979      * @since 3.10
8980      */
8981     public static String toRootUpperCase(final String source) {
8982         return source == null ? null : source.toUpperCase(Locale.ROOT);
8983     }
8984 
8985     /**
8986      * Converts a {@code byte[]} to a String using the specified character encoding.
8987      *
8988      * @param bytes
8989      *            the byte array to read from
8990      * @param charsetName
8991      *            the encoding to use, if null then use the platform default
8992      * @return a new String
8993      * @throws UnsupportedEncodingException
8994      *             Never thrown
8995      * @throws NullPointerException
8996      *             if the input is null
8997      * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8998      * @since 3.1
8999      */
9000     @Deprecated
9001     public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
9002         return new String(bytes, Charsets.toCharset(charsetName));
9003     }
9004 
9005     private static String toStringOrEmpty(final Object obj) {
9006         return Objects.toString(obj, EMPTY);
9007     }
9008 
9009     /**
9010      * Removes control characters (char &lt;= 32) from both
9011      * ends of this String, handling {@code null} by returning
9012      * {@code null}.
9013      *
9014      * <p>The String is trimmed using {@link String#trim()}.
9015      * Trim removes start and end characters &lt;= 32.
9016      * To strip whitespace use {@link #strip(String)}.</p>
9017      *
9018      * <p>To trim your choice of characters, use the
9019      * {@link #strip(String, String)} methods.</p>
9020      *
9021      * <pre>
9022      * StringUtils.trim(null)          = null
9023      * StringUtils.trim("")            = ""
9024      * StringUtils.trim("     ")       = ""
9025      * StringUtils.trim("abc")         = "abc"
9026      * StringUtils.trim("    abc    ") = "abc"
9027      * </pre>
9028      *
9029      * @param str  the String to be trimmed, may be null
9030      * @return the trimmed string, {@code null} if null String input
9031      */
9032     public static String trim(final String str) {
9033         return str == null ? null : str.trim();
9034     }
9035 
9036     /**
9037      * Removes control characters (char &lt;= 32) from both
9038      * ends of this String returning an empty String ("") if the String
9039      * is empty ("") after the trim or if it is {@code null}.
9040      *
9041      * <p>The String is trimmed using {@link String#trim()}.
9042      * Trim removes start and end characters &lt;= 32.
9043      * To strip whitespace use {@link #stripToEmpty(String)}.
9044      *
9045      * <pre>
9046      * StringUtils.trimToEmpty(null)          = ""
9047      * StringUtils.trimToEmpty("")            = ""
9048      * StringUtils.trimToEmpty("     ")       = ""
9049      * StringUtils.trimToEmpty("abc")         = "abc"
9050      * StringUtils.trimToEmpty("    abc    ") = "abc"
9051      * </pre>
9052      *
9053      * @param str  the String to be trimmed, may be null
9054      * @return the trimmed String, or an empty String if {@code null} input
9055      * @since 2.0
9056      */
9057     public static String trimToEmpty(final String str) {
9058         return str == null ? EMPTY : str.trim();
9059     }
9060 
9061     /**
9062      * Removes control characters (char &lt;= 32) from both
9063      * ends of this String returning {@code null} if the String is
9064      * empty ("") after the trim or if it is {@code null}.
9065      *
9066      * <p>The String is trimmed using {@link String#trim()}.
9067      * Trim removes start and end characters &lt;= 32.
9068      * To strip whitespace use {@link #stripToNull(String)}.
9069      *
9070      * <pre>
9071      * StringUtils.trimToNull(null)          = null
9072      * StringUtils.trimToNull("")            = null
9073      * StringUtils.trimToNull("     ")       = null
9074      * StringUtils.trimToNull("abc")         = "abc"
9075      * StringUtils.trimToNull("    abc    ") = "abc"
9076      * </pre>
9077      *
9078      * @param str  the String to be trimmed, may be null
9079      * @return the trimmed String,
9080      *  {@code null} if only chars &lt;= 32, empty or null String input
9081      * @since 2.0
9082      */
9083     public static String trimToNull(final String str) {
9084         final String ts = trim(str);
9085         return isEmpty(ts) ? null : ts;
9086     }
9087 
9088     /**
9089      * Truncates a String. This will turn
9090      * "Now is the time for all good men" into "Now is the time for".
9091      *
9092      * <p>Specifically:</p>
9093      * <ul>
9094      *   <li>If {@code str} is less than {@code maxWidth} characters
9095      *       long, return it.</li>
9096      *   <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
9097      *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9098      *       {@link IllegalArgumentException}.</li>
9099      *   <li>In no case will it return a String of length greater than
9100      *       {@code maxWidth}.</li>
9101      * </ul>
9102      *
9103      * <pre>
9104      * StringUtils.truncate(null, 0)       = null
9105      * StringUtils.truncate(null, 2)       = null
9106      * StringUtils.truncate("", 4)         = ""
9107      * StringUtils.truncate("abcdefg", 4)  = "abcd"
9108      * StringUtils.truncate("abcdefg", 6)  = "abcdef"
9109      * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
9110      * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
9111      * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
9112      * </pre>
9113      *
9114      * @param str  the String to truncate, may be null
9115      * @param maxWidth  maximum length of result String, must be positive
9116      * @return truncated String, {@code null} if null String input
9117      * @throws IllegalArgumentException If {@code maxWidth} is less than {@code 0}
9118      * @since 3.5
9119      */
9120     public static String truncate(final String str, final int maxWidth) {
9121         return truncate(str, 0, maxWidth);
9122     }
9123 
9124     /**
9125      * Truncates a String. This will turn
9126      * "Now is the time for all good men" into "is the time for all".
9127      *
9128      * <p>Works like {@code truncate(String, int)}, but allows you to specify
9129      * a "left edge" offset.
9130      *
9131      * <p>Specifically:</p>
9132      * <ul>
9133      *   <li>If {@code str} is less than {@code maxWidth} characters
9134      *       long, return it.</li>
9135      *   <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
9136      *   <li>If {@code maxWidth} is less than {@code 0}, throw an
9137      *       {@link IllegalArgumentException}.</li>
9138      *   <li>If {@code offset} is less than {@code 0}, throw an
9139      *       {@link IllegalArgumentException}.</li>
9140      *   <li>In no case will it return a String of length greater than
9141      *       {@code maxWidth}.</li>
9142      * </ul>
9143      *
9144      * <pre>
9145      * StringUtils.truncate(null, 0, 0) = null
9146      * StringUtils.truncate(null, 2, 4) = null
9147      * StringUtils.truncate("", 0, 10) = ""
9148      * StringUtils.truncate("", 2, 10) = ""
9149      * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
9150      * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
9151      * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
9152      * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
9153      * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
9154      * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = throws an IllegalArgumentException
9155      * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = throws an IllegalArgumentException
9156      * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
9157      * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
9158      * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
9159      * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
9160      * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
9161      * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
9162      * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
9163      * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
9164      * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
9165      * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
9166      * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
9167      * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
9168      * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
9169      * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
9170      * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
9171      * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
9172      * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
9173      * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
9174      * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
9175      * </pre>
9176      *
9177      * @param str  the String to truncate, may be null
9178      * @param offset  left edge of source String
9179      * @param maxWidth  maximum length of result String, must be positive
9180      * @return truncated String, {@code null} if null String input
9181      * @throws IllegalArgumentException If {@code offset} or {@code maxWidth} is less than {@code 0}
9182      * @since 3.5
9183      */
9184     public static String truncate(final String str, final int offset, final int maxWidth) {
9185         if (offset < 0) {
9186             throw new IllegalArgumentException("offset cannot be negative");
9187         }
9188         if (maxWidth < 0) {
9189             throw new IllegalArgumentException("maxWith cannot be negative");
9190         }
9191         if (str == null) {
9192             return null;
9193         }
9194         if (offset > str.length()) {
9195             return EMPTY;
9196         }
9197         if (str.length() > maxWidth) {
9198             final int ix = Math.min(offset + maxWidth, str.length());
9199             return str.substring(offset, ix);
9200         }
9201         return str.substring(offset);
9202     }
9203 
9204     /**
9205      * Uncapitalizes a String, changing the first character to lower case as
9206      * per {@link Character#toLowerCase(int)}. No other characters are changed.
9207      *
9208      * <p>For a word based algorithm, see {@link org.apache.commons.text.WordUtils#uncapitalize(String)}.
9209      * A {@code null} input String returns {@code null}.</p>
9210      *
9211      * <pre>
9212      * StringUtils.uncapitalize(null)  = null
9213      * StringUtils.uncapitalize("")    = ""
9214      * StringUtils.uncapitalize("cat") = "cat"
9215      * StringUtils.uncapitalize("Cat") = "cat"
9216      * StringUtils.uncapitalize("CAT") = "cAT"
9217      * </pre>
9218      *
9219      * @param str the String to uncapitalize, may be null
9220      * @return the uncapitalized String, {@code null} if null String input
9221      * @see org.apache.commons.text.WordUtils#uncapitalize(String)
9222      * @see #capitalize(String)
9223      * @since 2.0
9224      */
9225     public static String uncapitalize(final String str) {
9226         final int strLen = length(str);
9227         if (strLen == 0) {
9228             return str;
9229         }
9230 
9231         final int firstCodePoint = str.codePointAt(0);
9232         final int newCodePoint = Character.toLowerCase(firstCodePoint);
9233         if (firstCodePoint == newCodePoint) {
9234             // already capitalized
9235             return str;
9236         }
9237 
9238         final int[] newCodePoints = new int[strLen]; // cannot be longer than the char array
9239         int outOffset = 0;
9240         newCodePoints[outOffset++] = newCodePoint; // copy the first code point
9241         for (int inOffset = Character.charCount(firstCodePoint); inOffset < strLen; ) {
9242             final int codePoint = str.codePointAt(inOffset);
9243             newCodePoints[outOffset++] = codePoint; // copy the remaining ones
9244             inOffset += Character.charCount(codePoint);
9245          }
9246         return new String(newCodePoints, 0, outOffset);
9247     }
9248 
9249     /**
9250      * Unwraps a given string from a character.
9251      *
9252      * <pre>
9253      * StringUtils.unwrap(null, null)         = null
9254      * StringUtils.unwrap(null, '\0')         = null
9255      * StringUtils.unwrap(null, '1')          = null
9256      * StringUtils.unwrap("a", 'a')           = "a"
9257      * StringUtils.unwrap("aa", 'a')           = ""
9258      * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
9259      * StringUtils.unwrap("AABabcBAA", 'A')   = "ABabcBA"
9260      * StringUtils.unwrap("A", '#')           = "A"
9261      * StringUtils.unwrap("#A", '#')          = "#A"
9262      * StringUtils.unwrap("A#", '#')          = "A#"
9263      * </pre>
9264      *
9265      * @param str
9266      *          the String to be unwrapped, can be null
9267      * @param wrapChar
9268      *          the character used to unwrap
9269      * @return unwrapped String or the original string
9270      *          if it is not quoted properly with the wrapChar
9271      * @since 3.6
9272      */
9273     public static String unwrap(final String str, final char wrapChar) {
9274         if (isEmpty(str) || wrapChar == CharUtils.NUL || str.length() == 1) {
9275             return str;
9276         }
9277 
9278         if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9279             final int startIndex = 0;
9280             final int endIndex = str.length() - 1;
9281 
9282             return str.substring(startIndex + 1, endIndex);
9283         }
9284 
9285         return str;
9286     }
9287 
9288     /**
9289      * Unwraps a given string from another string.
9290      *
9291      * <pre>
9292      * StringUtils.unwrap(null, null)         = null
9293      * StringUtils.unwrap(null, "")           = null
9294      * StringUtils.unwrap(null, "1")          = null
9295      * StringUtils.unwrap("a", "a")           = "a"
9296      * StringUtils.unwrap("aa", "a")          = ""
9297      * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
9298      * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
9299      * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
9300      * StringUtils.unwrap("A", "#")           = "A"
9301      * StringUtils.unwrap("#A", "#")          = "#A"
9302      * StringUtils.unwrap("A#", "#")          = "A#"
9303      * </pre>
9304      *
9305      * @param str
9306      *          the String to be unwrapped, can be null
9307      * @param wrapToken
9308      *          the String used to unwrap
9309      * @return unwrapped String or the original string
9310      *          if it is not quoted properly with the wrapToken
9311      * @since 3.6
9312      */
9313     public static String unwrap(final String str, final String wrapToken) {
9314         if (isEmpty(str) || isEmpty(wrapToken) || str.length() < 2 * wrapToken.length()) {
9315             return str;
9316         }
9317 
9318         if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9319             return str.substring(wrapToken.length(), str.lastIndexOf(wrapToken));
9320         }
9321 
9322         return str;
9323     }
9324 
9325     /**
9326      * Converts a String to upper case as per {@link String#toUpperCase()}.
9327      *
9328      * <p>A {@code null} input String returns {@code null}.</p>
9329      *
9330      * <pre>
9331      * StringUtils.upperCase(null)  = null
9332      * StringUtils.upperCase("")    = ""
9333      * StringUtils.upperCase("aBc") = "ABC"
9334      * </pre>
9335      *
9336      * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
9337      * the result of this method is affected by the current locale.
9338      * For platform-independent case transformations, the method {@link #upperCase(String, Locale)}
9339      * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
9340      *
9341      * @param str  the String to upper case, may be null
9342      * @return the upper-cased String, {@code null} if null String input
9343      */
9344     public static String upperCase(final String str) {
9345         if (str == null) {
9346             return null;
9347         }
9348         return str.toUpperCase();
9349     }
9350 
9351     /**
9352      * Converts a String to upper case as per {@link String#toUpperCase(Locale)}.
9353      *
9354      * <p>A {@code null} input String returns {@code null}.</p>
9355      *
9356      * <pre>
9357      * StringUtils.upperCase(null, Locale.ENGLISH)  = null
9358      * StringUtils.upperCase("", Locale.ENGLISH)    = ""
9359      * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
9360      * </pre>
9361      *
9362      * @param str  the String to upper case, may be null
9363      * @param locale  the locale that defines the case transformation rules, must not be null
9364      * @return the upper-cased String, {@code null} if null String input
9365      * @since 2.5
9366      */
9367     public static String upperCase(final String str, final Locale locale) {
9368         if (str == null) {
9369             return null;
9370         }
9371         return str.toUpperCase(LocaleUtils.toLocale(locale));
9372     }
9373 
9374     /**
9375      * Returns the string representation of the {@code char} array or null.
9376      *
9377      * @param value the character array.
9378      * @return a String or null
9379      * @see String#valueOf(char[])
9380      * @since 3.9
9381      */
9382     public static String valueOf(final char[] value) {
9383         return value == null ? null : String.valueOf(value);
9384     }
9385 
9386     /**
9387      * Wraps a string with a char.
9388      *
9389      * <pre>
9390      * StringUtils.wrap(null, *)        = null
9391      * StringUtils.wrap("", *)          = ""
9392      * StringUtils.wrap("ab", '\0')     = "ab"
9393      * StringUtils.wrap("ab", 'x')      = "xabx"
9394      * StringUtils.wrap("ab", '\'')     = "'ab'"
9395      * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
9396      * </pre>
9397      *
9398      * @param str
9399      *            the string to be wrapped, may be {@code null}
9400      * @param wrapWith
9401      *            the char that will wrap {@code str}
9402      * @return the wrapped string, or {@code null} if {@code str==null}
9403      * @since 3.4
9404      */
9405     public static String wrap(final String str, final char wrapWith) {
9406 
9407         if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9408             return str;
9409         }
9410 
9411         return wrapWith + str + wrapWith;
9412     }
9413 
9414     /**
9415      * Wraps a String with another String.
9416      *
9417      * <p>
9418      * A {@code null} input String returns {@code null}.
9419      * </p>
9420      *
9421      * <pre>
9422      * StringUtils.wrap(null, *)         = null
9423      * StringUtils.wrap("", *)           = ""
9424      * StringUtils.wrap("ab", null)      = "ab"
9425      * StringUtils.wrap("ab", "x")       = "xabx"
9426      * StringUtils.wrap("ab", "\"")      = "\"ab\""
9427      * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
9428      * StringUtils.wrap("ab", "'")       = "'ab'"
9429      * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
9430      * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9431      * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
9432      * </pre>
9433      *
9434      * @param str
9435      *            the String to be wrapper, may be null
9436      * @param wrapWith
9437      *            the String that will wrap str
9438      * @return wrapped String, {@code null} if null String input
9439      * @since 3.4
9440      */
9441     public static String wrap(final String str, final String wrapWith) {
9442 
9443         if (isEmpty(str) || isEmpty(wrapWith)) {
9444             return str;
9445         }
9446 
9447         return wrapWith.concat(str).concat(wrapWith);
9448     }
9449 
9450     /**
9451      * Wraps a string with a char if that char is missing from the start or end of the given string.
9452      *
9453      * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9454      *
9455      * <pre>
9456      * StringUtils.wrapIfMissing(null, *)        = null
9457      * StringUtils.wrapIfMissing("", *)          = ""
9458      * StringUtils.wrapIfMissing("ab", '\0')     = "ab"
9459      * StringUtils.wrapIfMissing("ab", 'x')      = "xabx"
9460      * StringUtils.wrapIfMissing("ab", '\'')     = "'ab'"
9461      * StringUtils.wrapIfMissing("\"ab\"", '\"') = "\"ab\""
9462      * StringUtils.wrapIfMissing("/", '/')  = "/"
9463      * StringUtils.wrapIfMissing("a/b/c", '/')  = "/a/b/c/"
9464      * StringUtils.wrapIfMissing("/a/b/c", '/')  = "/a/b/c/"
9465      * StringUtils.wrapIfMissing("a/b/c/", '/')  = "/a/b/c/"
9466      * </pre>
9467      *
9468      * @param str
9469      *            the string to be wrapped, may be {@code null}
9470      * @param wrapWith
9471      *            the char that will wrap {@code str}
9472      * @return the wrapped string, or {@code null} if {@code str==null}
9473      * @since 3.5
9474      */
9475     public static String wrapIfMissing(final String str, final char wrapWith) {
9476         if (isEmpty(str) || wrapWith == CharUtils.NUL) {
9477             return str;
9478         }
9479         final boolean wrapStart = str.charAt(0) != wrapWith;
9480         final boolean wrapEnd = str.charAt(str.length() - 1) != wrapWith;
9481         if (!wrapStart && !wrapEnd) {
9482             return str;
9483         }
9484 
9485         final StringBuilder builder = new StringBuilder(str.length() + 2);
9486         if (wrapStart) {
9487             builder.append(wrapWith);
9488         }
9489         builder.append(str);
9490         if (wrapEnd) {
9491             builder.append(wrapWith);
9492         }
9493         return builder.toString();
9494     }
9495 
9496     /**
9497      * Wraps a string with a string if that string is missing from the start or end of the given string.
9498      *
9499      * <p>A new {@link String} will not be created if {@code str} is already wrapped.</p>
9500      *
9501      * <pre>
9502      * StringUtils.wrapIfMissing(null, *)         = null
9503      * StringUtils.wrapIfMissing("", *)           = ""
9504      * StringUtils.wrapIfMissing("ab", null)      = "ab"
9505      * StringUtils.wrapIfMissing("ab", "x")       = "xabx"
9506      * StringUtils.wrapIfMissing("ab", "\"")      = "\"ab\""
9507      * StringUtils.wrapIfMissing("\"ab\"", "\"")  = "\"ab\""
9508      * StringUtils.wrapIfMissing("ab", "'")       = "'ab'"
9509      * StringUtils.wrapIfMissing("'abcd'", "'")   = "'abcd'"
9510      * StringUtils.wrapIfMissing("\"abcd\"", "'") = "'\"abcd\"'"
9511      * StringUtils.wrapIfMissing("'abcd'", "\"")  = "\"'abcd'\""
9512      * StringUtils.wrapIfMissing("/", "/")  = "/"
9513      * StringUtils.wrapIfMissing("a/b/c", "/")  = "/a/b/c/"
9514      * StringUtils.wrapIfMissing("/a/b/c", "/")  = "/a/b/c/"
9515      * StringUtils.wrapIfMissing("a/b/c/", "/")  = "/a/b/c/"
9516      * </pre>
9517      *
9518      * @param str
9519      *            the string to be wrapped, may be {@code null}
9520      * @param wrapWith
9521      *            the string that will wrap {@code str}
9522      * @return the wrapped string, or {@code null} if {@code str==null}
9523      * @since 3.5
9524      */
9525     public static String wrapIfMissing(final String str, final String wrapWith) {
9526         if (isEmpty(str) || isEmpty(wrapWith)) {
9527             return str;
9528         }
9529 
9530         final boolean wrapStart = !str.startsWith(wrapWith);
9531         final boolean wrapEnd = !str.endsWith(wrapWith);
9532         if (!wrapStart && !wrapEnd) {
9533             return str;
9534         }
9535 
9536         final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9537         if (wrapStart) {
9538             builder.append(wrapWith);
9539         }
9540         builder.append(str);
9541         if (wrapEnd) {
9542             builder.append(wrapWith);
9543         }
9544         return builder.toString();
9545     }
9546 
9547     /**
9548      * {@link StringUtils} instances should NOT be constructed in
9549      * standard programming. Instead, the class should be used as
9550      * {@code StringUtils.trim(" foo ");}.
9551      *
9552      * <p>This constructor is public to permit tools that require a JavaBean
9553      * instance to operate.</p>
9554      */
9555     public StringUtils() {
9556     }
9557 
9558 }