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